This file is part of MXE. See index.html for further information. From 990c4a3ec111502fcb4738a6772e90d294cce2cd Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Fri, 11 Jan 2013 00:30:41 +0100 Subject: [PATCH 01/10] consolidate generation of metafile install targets Metafiles such as .prl and .pc files contain paths that have to be adjusted during installation. The same code is used for unix and windows so move it into the base class. Change-Id: I82db89ec83820a4fa0214ba15e7cd63438f6dc91 Reviewed-by: Oswald Buddenhagen (cherry picked from commit d089ecb711afcd13a32e24103e270ba000cdc68c) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 9d85205..b687f04 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -3285,4 +3285,25 @@ MakefileGenerator::writePkgConfigFile() t << endl; } +QString MakefileGenerator::installMetaFile(const ProKey &replace_rule, const QString &src, const QString &dst) +{ + QString ret; + if (project->isEmpty(replace_rule) + || project->isActiveConfig("no_sed_meta_install") + || project->isEmpty("QMAKE_STREAM_EDITOR")) { + ret += "-$(INSTALL_FILE) \"" + src + "\" \"" + dst + "\""; + } else { + ret += "-$(SED)"; + const ProStringList &replace_rules = project->values(replace_rule); + for (int r = 0; r < replace_rules.size(); ++r) { + const ProString match = project->first(ProKey(replace_rules.at(r) + ".match")), + replace = project->first(ProKey(replace_rules.at(r) + ".replace")); + if (!match.isEmpty() /*&& match != replace*/) + ret += " -e \"s," + match + "," + replace + ",g\""; + } + ret += " \"" + src + "\" >\"" + dst + "\""; + } + return ret; +} + QT_END_NAMESPACE diff --git a/qmake/generators/makefile.h b/qmake/generators/makefile.h index 0b471d0..a686d8f 100644 --- a/qmake/generators/makefile.h +++ b/qmake/generators/makefile.h @@ -248,6 +248,8 @@ protected: inline QStringList fileFixify(const QStringList& files, FileFixifyType fix, bool canon=true) const { return fileFixify(files, QString(), QString(), fix, canon); } + QString installMetaFile(const ProKey &replace_rule, const QString &src, const QString &dst); + public: MakefileGenerator(); virtual ~MakefileGenerator(); diff --git a/qmake/generators/unix/unixmake.cpp b/qmake/generators/unix/unixmake.cpp index 8a1a29c..28c4fba 100644 --- a/qmake/generators/unix/unixmake.cpp +++ b/qmake/generators/unix/unixmake.cpp @@ -868,32 +868,15 @@ UnixMakefileGenerator::defaultInstall(const QString &t) if(!uninst.isEmpty()) uninst.append("\n\t"); uninst.append("-$(DEL_FILE) \"" + dst_meta + "\""); - const ProKey replace_rule("QMAKE_" + type.toUpper() + "_INSTALL_REPLACE"); const QString dst_meta_dir = fileInfo(dst_meta).path(); if(!dst_meta_dir.isEmpty()) { if(!ret.isEmpty()) ret += "\n\t"; ret += mkdir_p_asstring(dst_meta_dir, true); } - QString install_meta = "$(INSTALL_FILE) \"" + src_meta + "\" \"" + dst_meta + "\""; - if(project->isEmpty(replace_rule) || project->isActiveConfig("no_sed_meta_install")) { - if(!ret.isEmpty()) - ret += "\n\t"; - ret += "-" + install_meta; - } else { - if(!ret.isEmpty()) - ret += "\n\t"; - ret += "-$(SED)"; - const ProStringList &replace_rules = project->values(replace_rule); - for(int r = 0; r < replace_rules.size(); ++r) { - const ProString &match = project->first(ProKey(replace_rules.at(r) + ".match")), - &replace = project->first(ProKey(replace_rules.at(r) + ".replace")); - if(!match.isEmpty() /*&& match != replace*/) - ret += " -e \"s," + match + "," + replace + ",g\""; - } - ret += " \"" + src_meta + "\" >\"" + dst_meta + "\""; - //ret += " || " + install_meta; - } + if (!ret.isEmpty()) + ret += "\n\t"; + ret += installMetaFile(ProKey("QMAKE_" + type.toUpper() + "_INSTALL_REPLACE"), src_meta, dst_meta); } } } diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index bda035e..3b2c620 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -842,22 +842,7 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) } if(!ret.isEmpty()) ret += "\n\t"; - const ProKey replace_rule("QMAKE_PKGCONFIG_INSTALL_REPLACE"); - if (project->isEmpty(replace_rule) - || project->isActiveConfig("no_sed_meta_install") - || project->isEmpty("QMAKE_STREAM_EDITOR")) { - ret += "-$(INSTALL_FILE) \"" + pkgConfigFileName(true) + "\" \"" + dst_pc + "\""; - } else { - ret += "-$(SED)"; - const ProStringList &replace_rules = project->values(replace_rule); - for (int r = 0; r < replace_rules.size(); ++r) { - const ProString match = project->first(ProKey(replace_rules.at(r) + ".match")), - replace = project->first(ProKey(replace_rules.at(r) + ".replace")); - if (!match.isEmpty() /*&& match != replace*/) - ret += " -e \"s," + match + "," + replace + ",g\""; - } - ret += " \"" + pkgConfigFileName(true) + "\" >\"" + dst_pc + "\""; - } + ret += installMetaFile(ProKey("QMAKE_PKGCONFIG_INSTALL_REPLACE"), pkgConfigFileName(true), dst_pc); if(!uninst.isEmpty()) uninst.append("\n\t"); uninst.append("-$(DEL_FILE) \"" + dst_pc + "\""); -- 1.8.1.4 From 569deb7d1a39e17fb5635411a68d374233f74818 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Sun, 27 Jan 2013 14:03:16 +0100 Subject: [PATCH 02/10] don't prematurely reduce LIBS when adding sql link lists It's possible that different database libraries share dependencies. We need to keep their link lists intact here so that QtSql's .prl and .pc files will have them in the right order. Particularly important when building the drivers into QtSql and using static linking. Change-Id: Id371b127099f2790fe7cccd0c7059607600f447d Reviewed-by: Oswald Buddenhagen (cherry picked from commit 9ef48277f959ff759bd9fba36c907ef5ed67f5b1) diff --git a/src/sql/drivers/mysql/qsql_mysql.pri b/src/sql/drivers/mysql/qsql_mysql.pri index c9ec257..0423eb4 100644 --- a/src/sql/drivers/mysql/qsql_mysql.pri +++ b/src/sql/drivers/mysql/qsql_mysql.pri @@ -13,7 +13,7 @@ unix { else:LIBS += -lmysqlclient } } else { - LIBS *= $$QT_LFLAGS_MYSQL + LIBS += $$QT_LFLAGS_MYSQL QMAKE_CXXFLAGS *= $$QT_CFLAGS_MYSQL } } else { diff --git a/src/sql/drivers/psql/qsql_psql.pri b/src/sql/drivers/psql/qsql_psql.pri index 6da3540..9b647d8 100644 --- a/src/sql/drivers/psql/qsql_psql.pri +++ b/src/sql/drivers/psql/qsql_psql.pri @@ -2,7 +2,7 @@ HEADERS += $$PWD/qsql_psql.h SOURCES += $$PWD/qsql_psql.cpp unix|win32-g++* { - LIBS *= $$QT_LFLAGS_PSQL + LIBS += $$QT_LFLAGS_PSQL !contains(LIBS, .*pq.*):LIBS += -lpq QMAKE_CXXFLAGS *= $$QT_CFLAGS_PSQL } else { diff --git a/src/sql/drivers/sqlite/qsql_sqlite.pri b/src/sql/drivers/sqlite/qsql_sqlite.pri index 7ad5936..a2e80d4 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.pri +++ b/src/sql/drivers/sqlite/qsql_sqlite.pri @@ -4,6 +4,6 @@ SOURCES += $$PWD/qsql_sqlite.cpp !system-sqlite:!contains(LIBS, .*sqlite3.*) { include($$PWD/../../../3rdparty/sqlite.pri) } else { - LIBS *= $$QT_LFLAGS_SQLITE + LIBS += $$QT_LFLAGS_SQLITE QMAKE_CXXFLAGS *= $$QT_CFLAGS_SQLITE } diff --git a/src/sql/drivers/tds/qsql_tds.pri b/src/sql/drivers/tds/qsql_tds.pri index 3b5a689..38aab2f 100644 --- a/src/sql/drivers/tds/qsql_tds.pri +++ b/src/sql/drivers/tds/qsql_tds.pri @@ -2,7 +2,7 @@ HEADERS += $$PWD/qsql_tds.h SOURCES += $$PWD/qsql_tds.cpp unix|win32-g++*: { - LIBS *= $$QT_LFLAGS_TDS + LIBS += $$QT_LFLAGS_TDS !contains(LIBS, .*sybdb.*):LIBS += -lsybdb QMAKE_CXXFLAGS *= $$QT_CFLAGS_TDS } else { -- 1.8.1.4 From a541a0a510b148b684cdb15da4e6a276e3c6ef83 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 29 Jan 2013 21:56:24 +0100 Subject: [PATCH 03/10] adjust paths in installed module metafiles from modular build Fully modular prefix build now puts the includes and libs into each module's own builddir, so the else branch was simply bogus. Replaced the else branch with the real base for modular builds. This allows the paths to be successfully replaced when installing metafiles. Change-Id: I056a923288965b560a4e9b0ba7add1aac912199f Reviewed-by: Oswald Buddenhagen (cherry picked from commit 0e1427b0a6c3d304aabecd3d33708ecb0544fdba) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 50e9469..3ade5a9 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -190,7 +190,7 @@ unix|win32-g++* { !isEmpty(_QMAKE_SUPER_CACHE_): \ rplbase = $$dirname(_QMAKE_SUPER_CACHE_)/[^/][^/]* else: \ - rplbase = $$[QT_INSTALL_PREFIX/get] + rplbase = $$MODULE_QMAKE_OUTDIR include_replace.match = $$rplbase/include include_replace.replace = $$[QT_INSTALL_HEADERS/raw] lib_replace.match = $$rplbase/lib -- 1.8.1.4 From facc35e0c2f6b51ad4cbcdfe79475db155ba52e5 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Fri, 11 Jan 2013 00:30:25 +0100 Subject: [PATCH 04/10] adjust paths in installed prl files for mingw Curiously, qmake could fix .prl and .pc files for unix, but only .pc files for MinGW. qt_module.prf seems to have known this. Task-number: QTBUG-28902 Change-Id: Ice9983a69813690c0d4b96ca11589440182569a0 Reviewed-by: Oswald Buddenhagen (cherry picked from commit 6d90c2e9cbfeeb560ffaeed94d908997f90d0877) diff --git a/mkspecs/features/qt_module.prf b/mkspecs/features/qt_module.prf index 3ade5a9..98e4b1a 100644 --- a/mkspecs/features/qt_module.prf +++ b/mkspecs/features/qt_module.prf @@ -196,11 +196,11 @@ unix|win32-g++* { lib_replace.match = $$rplbase/lib lib_replace.replace = $$[QT_INSTALL_LIBS/raw] QMAKE_PKGCONFIG_INSTALL_REPLACE += include_replace lib_replace + QMAKE_PRL_INSTALL_REPLACE += include_replace lib_replace } unix { CONFIG += create_libtool explicitlib - QMAKE_PRL_INSTALL_REPLACE += include_replace lib_replace QMAKE_LIBTOOL_LIBDIR = $$[QT_INSTALL_LIBS/raw] QMAKE_LIBTOOL_INSTALL_REPLACE += include_replace lib_replace } diff --git a/qmake/generators/win32/winmakefile.cpp b/qmake/generators/win32/winmakefile.cpp index 3b2c620..2270a00 100644 --- a/qmake/generators/win32/winmakefile.cpp +++ b/qmake/generators/win32/winmakefile.cpp @@ -825,7 +825,7 @@ QString Win32MakefileGenerator::defaultInstall(const QString &t) if(slsh != -1) dst_prl = dst_prl.right(dst_prl.length() - slsh - 1); dst_prl = filePrefixRoot(root, targetdir + dst_prl); - ret += "-$(INSTALL_FILE) \"" + project->first("QMAKE_INTERNAL_PRL_FILE") + "\" \"" + dst_prl + "\""; + ret += installMetaFile(ProKey("QMAKE_PRL_INSTALL_REPLACE"), project->first("QMAKE_INTERNAL_PRL_FILE").toQString(), dst_prl); if(!uninst.isEmpty()) uninst.append("\n\t"); uninst.append("-$(DEL_FILE) \"" + dst_prl + "\""); -- 1.8.1.4 From d6a4dcb0dd88fa6fb4c352d48bf0445341e7de35 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 29 Jan 2013 21:51:31 +0100 Subject: [PATCH 05/10] fix path adjustments in installed metafiles Task-number: QTBUG-28902 Change-Id: Ia70da8f0f0b7abb4ea2a46cb4068c0827888b322 Reviewed-by: Oswald Buddenhagen (cherry picked from commit 2be4d6ba022e1349b1b231ae852235f557c6fc20) diff --git a/mkspecs/features/qml_plugin.prf b/mkspecs/features/qml_plugin.prf index 7abd372..f9beabd 100644 --- a/mkspecs/features/qml_plugin.prf +++ b/mkspecs/features/qml_plugin.prf @@ -89,3 +89,12 @@ load(qt_targets) } load(qml_module) + +unix|win32-g++* { + !isEmpty(_QMAKE_SUPER_CACHE_): \ + lib_replace.match = $$dirname(_QMAKE_SUPER_CACHE_)/[^/][^/]*/lib + else: \ + lib_replace.match = $$eval(QT.$${CXX_MODULE}.libs) + lib_replace.replace = $$[QT_INSTALL_LIBS/raw] + QMAKE_PRL_INSTALL_REPLACE += lib_replace +} diff --git a/mkspecs/features/qt_plugin.prf b/mkspecs/features/qt_plugin.prf index 4861576..2ec523d 100644 --- a/mkspecs/features/qt_plugin.prf +++ b/mkspecs/features/qt_plugin.prf @@ -58,3 +58,13 @@ load(qt_targets) wince*:LIBS += $$QMAKE_LIBS_GUI QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF + +unix|win32-g++* { + !isEmpty(_QMAKE_SUPER_CACHE_): \ + rplbase = $$dirname(_QMAKE_SUPER_CACHE_)/[^/][^/]* + else: \ + rplbase = $$MODULE_QMAKE_OUTDIR + lib_replace.match = $$rplbase/lib + lib_replace.replace = $$[QT_INSTALL_LIBS/raw] + QMAKE_PRL_INSTALL_REPLACE += lib_replace +} diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index 32eae0b..b8c920b 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -25,3 +25,9 @@ TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end load(qt_targets) wince*:QMAKE_POST_LINK = + +unix|win32-g++* { + lib_replace.match = $$[QT_INSTALL_LIBS/get] + lib_replace.replace = $$[QT_INSTALL_LIBS/raw] + QMAKE_PRL_INSTALL_REPLACE += lib_replace +} -- 1.8.1.4 From e2d6cdad6a36928f1415e3e20f5de4544a14058e Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Thu, 31 Jan 2013 17:24:50 +0100 Subject: [PATCH 06/10] fix build failures on mingw caused by name clash In mingw.org, basetyps.h contains #define interface _COM_interface which clashes with function parameter names in qdbusmessage.h. Although there is no clash when building qtbase itself, the clash makes building qttools 5.0.1 fail. Presumably this could also affect other applications. Taken from 2cc9a9a51d6742708b1ea41c7338755e2a0ee9e9 which solves the same problem in another header. Change-Id: I802d5c673b544fb3a17e9273030876928faa5c46 Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira (cherry picked from commit 3ba61d9baa569ea69e41a943981680c09c521ff7) diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h index 386078d..c7daf80 100644 --- a/src/dbus/qdbusmessage.h +++ b/src/dbus/qdbusmessage.h @@ -49,6 +49,10 @@ #ifndef QT_NO_DBUS +#if defined(Q_OS_WIN) && defined(interface) +# undef interface +#endif + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -- 1.8.1.4 From a3e569cc2483f647b71e8bd35035ebeb662d0549 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Tue, 26 Feb 2013 13:23:33 +0100 Subject: [PATCH 07/10] use pkg-config for freetype Change-Id: Id2f78ed9dbdcacd570eb25982cbd700d0437542a diff --git a/src/platformsupport/fontdatabases/basic/basic.pri b/src/platformsupport/fontdatabases/basic/basic.pri index 6b5f6d0..d21f4e3 100644 --- a/src/platformsupport/fontdatabases/basic/basic.pri +++ b/src/platformsupport/fontdatabases/basic/basic.pri @@ -83,5 +83,7 @@ contains(QT_CONFIG, freetype) { } else:contains(QT_CONFIG, system-freetype) { # pull in the proper freetype2 include directory include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) + CONFIG += link_pkgconfig + PKGCONFIG += freetype2 } -- 1.8.1.4 From f1943915d6179b39418d1d051e316f2862249fac Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Sat, 22 Dec 2012 17:45:34 +0100 Subject: [PATCH 08/10] WIP: qmake writeFile(): work around concurrent QDir::mkpath() failure This actually happened when building qtimageformats with make -j4. Failure in mkspecs/features/qt_plugin.prf: write_file($$MODULE_PRI, MODULE_PRI_CONT)|error("Aborting.") with make -j4. Change-Id: Ibc685f613d721e178e6aff408905d77b0ce1740a diff --git a/qmake/library/qmakebuiltins.cpp b/qmake/library/qmakebuiltins.cpp index bafa867..d8b03f7 100644 --- a/qmake/library/qmakebuiltins.cpp +++ b/qmake/library/qmakebuiltins.cpp @@ -310,9 +310,17 @@ QMakeEvaluator::writeFile(const QString &ctx, const QString &fn, QIODevice::Open { QFileInfo qfi(fn); if (!QDir::current().mkpath(qfi.path())) { - evalError(fL1S("Cannot create %1directory %2.") - .arg(ctx, QDir::toNativeSeparators(qfi.path()))); - return ReturnFalse; + // could have failed due to concurrent mkpath attempt +#ifdef Q_OS_WIN + Sleep(1000); +#else + sleep(1); +#endif + if (!qfi.dir().exists()) { + evalError(fL1S("Cannot create %1directory %2.") + .arg(ctx, QDir::toNativeSeparators(qfi.path()))); + return ReturnFalse; + } } QString errStr; if (!doWriteFile(qfi.filePath(), mode, contents, &errStr)) { -- 1.8.1.4 From 2548db5e688d74fb2180464a2a03b56794fe4e5b Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Sat, 26 Jan 2013 23:09:24 +0100 Subject: [PATCH 09/10] fix QSqlTableModel::headerData() for empty query with inserted row QSqlQueryModel::headerData() relied on virtual indexInQuery() to detect whether the requested column at row 0 mapped to an index in the query. This failed when row 0 was a pending insert managed by QSqlTableModel, and therefore not in the query. The only thing that matters here is the column. Task-number: QTBUG-29108 Change-Id: I3e0ae85ba223e444781ec8033386d394bb44f0e8 Reviewed-by: Andy Shaw Reviewed-by: Mark Brand (cherry picked from commit a694b9f8d204d6555caf4e30dbd18f536859c5bd) diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp index c49a1f2..cefc777 100644 --- a/src/sql/models/qsqlquerymodel.cpp +++ b/src/sql/models/qsqlquerymodel.cpp @@ -95,6 +95,13 @@ void QSqlQueryModelPrivate::initColOffsets(int size) memset(colOffsets.data(), 0, colOffsets.size() * sizeof(int)); } +int QSqlQueryModelPrivate::columnInQuery(int modelColumn) const +{ + if (modelColumn < 0 || modelColumn >= rec.count() || !rec.isGenerated(modelColumn) || modelColumn >= colOffsets.size()) + return -1; + return modelColumn - colOffsets[modelColumn]; +} + /*! \class QSqlQueryModel \brief The QSqlQueryModel class provides a read-only data model for SQL @@ -370,11 +377,7 @@ QVariant QSqlQueryModel::headerData(int section, Qt::Orientation orientation, in val = d->headers.value(section).value(Qt::EditRole); if (val.isValid()) return val; - - // See if it's an inserted column (iiq.column() != -1) - QModelIndex dItem = indexInQuery(createIndex(0, section)); - - if (role == Qt::DisplayRole && d->rec.count() > section && dItem.column() != -1) + if (role == Qt::DisplayRole && d->rec.count() > section && d->columnInQuery(section) != -1) return d->rec.fieldName(section); } return QAbstractItemModel::headerData(section, orientation, role); @@ -668,12 +671,10 @@ bool QSqlQueryModel::removeColumns(int column, int count, const QModelIndex &par QModelIndex QSqlQueryModel::indexInQuery(const QModelIndex &item) const { Q_D(const QSqlQueryModel); - if (item.column() < 0 || item.column() >= d->rec.count() - || !d->rec.isGenerated(item.column()) - || item.column() >= d->colOffsets.size()) + int modelColumn = d->columnInQuery(item.column()); + if (modelColumn < 0) return QModelIndex(); - return createIndex(item.row(), item.column() - d->colOffsets[item.column()], - item.internalPointer()); + return createIndex(item.row(), modelColumn, item.internalPointer()); } QT_END_NAMESPACE diff --git a/src/sql/models/qsqlquerymodel_p.h b/src/sql/models/qsqlquerymodel_p.h index 2e10130..0f2e24e 100644 --- a/src/sql/models/qsqlquerymodel_p.h +++ b/src/sql/models/qsqlquerymodel_p.h @@ -72,6 +72,7 @@ public: void prefetch(int); void initColOffsets(int size); + int columnInQuery(int modelColumn) const; mutable QSqlQuery query; mutable QSqlError error; diff --git a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp index a3341ff..a973281 100644 --- a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp @@ -1433,6 +1433,14 @@ void tst_QSqlTableModel::emptyTable() QVERIFY_SQL(model, select()); QCOMPARE(model.rowCount(), 0); QCOMPARE(model.columnCount(), 1); + + // QTBUG-29108: check correct horizontal header for empty query with pending insert + QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), QString("id")); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); + model.insertRow(0); + QCOMPARE(model.rowCount(), 1); + QCOMPARE(model.headerData(0, Qt::Horizontal).toString(), QString("id")); + model.revertAll(); } void tst_QSqlTableModel::tablesAndSchemas() -- 1.8.1.4 From f8714544492bf37b23e3d52d3a06d3dc38a53840 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Wed, 30 Jan 2013 00:39:53 +0100 Subject: [PATCH 10/10] QSqlTableModel::setData(): fix non-change detection Commit 10ff9de91bedf93852f13a58287afd8831644759 introduced the optimization of ignoring non-changes, but it overshot the mark. It neglected to consider that QVariant's equality operator does not compare the null flag. It also failed to consider that setData() has a useful side effect of setting the generated flag in a column of a pending INSERT. This is important when the application actually wants a NULL to be inserted into the column. Task-number: QTBUG-29217 Change-Id: I1368f7acc21eebfeb5a8d23746fc38f6f30fd395 Reviewed-by: Andy Shaw Reviewed-by: Mark Brand (cherry picked from commit 33c212b7d25726b78c4bf630548a76feaab872f0) diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index 27e1c3e..8569cbc 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -587,7 +587,10 @@ bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, in if (!(flags(index) & Qt::ItemIsEditable)) return false; - if (QSqlTableModel::data(index, role) == value) + const QVariant oldValue = QSqlTableModel::data(index, role); + if (value == oldValue + && value.isNull() == oldValue.isNull() + && d->cache.value(index.row()).op() != QSqlTableModelPrivate::Insert) return true; QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()]; diff --git a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp index a973281..9f6f232 100644 --- a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp @@ -83,6 +83,8 @@ private slots: void insertColumns(); void submitAll_data() { generic_data(); } void submitAll(); + void setData_data() { generic_data(); } + void setData(); void setRecord_data() { generic_data(); } void setRecord(); void setRecordReimpl_data() { generic_data(); } @@ -501,6 +503,77 @@ void tst_QSqlTableModel::insertColumns() QCOMPARE(model.data(model.index(3, 5)), QVariant()); } +void tst_QSqlTableModel::setData() +{ + QFETCH(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QSqlTableModel model(0, db); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); + model.setTable(test); + model.setSort(0, Qt::AscendingOrder); + QVERIFY_SQL(model, select()); + + // initial state + QModelIndex idx = model.index(0, 0); + QVariant val = model.data(idx); + QVERIFY(val == int(1)); + QVERIFY(!val.isNull()); + QFAIL_SQL(model, isDirty()); + + // change 1 to 0 + idx = model.index(0, 0); + QVERIFY_SQL(model, setData(idx, int(0))); + val = model.data(idx); + QVERIFY(val == int(0)); + QVERIFY(!val.isNull()); + QVERIFY_SQL(model, isDirty(idx)); + QVERIFY_SQL(model, submitAll()); + + // change 0 to NULL + idx = model.index(0, 0); + QVERIFY_SQL(model, setData(idx, QVariant(QVariant::Int))); + val = model.data(idx); + QVERIFY(val == QVariant(QVariant::Int)); + QVERIFY(val.isNull()); + QVERIFY_SQL(model, isDirty(idx)); + QVERIFY_SQL(model, submitAll()); + + // change NULL to 0 + idx = model.index(0, 0); + QVERIFY_SQL(model, setData(idx, int(0))); + val = model.data(idx); + QVERIFY(val == int(0)); + QVERIFY(!val.isNull()); + QVERIFY_SQL(model, isDirty(idx)); + QVERIFY_SQL(model, submitAll()); + + // ignore unchanged 0 to 0 + idx = model.index(0, 0); + QVERIFY_SQL(model, setData(idx, int(0))); + val = model.data(idx); + QVERIFY(val == int(0)); + QVERIFY(!val.isNull()); + QFAIL_SQL(model, isDirty(idx)); + + // pending INSERT + QVERIFY_SQL(model, insertRow(0)); + // initial state + idx = model.index(0, 0); + QSqlRecord rec = model.record(0); + QVERIFY(rec.value(0) == QVariant(QVariant::Int)); + QVERIFY(rec.isNull(0)); + QVERIFY(!rec.isGenerated(0)); + // unchanged value, but causes column to be included in INSERT + QVERIFY_SQL(model, setData(idx, QVariant(QVariant::Int))); + rec = model.record(0); + QVERIFY(rec.value(0) == QVariant(QVariant::Int)); + QVERIFY(rec.isNull(0)); + QVERIFY(rec.isGenerated(0)); + QVERIFY_SQL(model, submitAll()); +} + void tst_QSqlTableModel::setRecord() { QFETCH(QString, dbName); -- 1.8.1.4