Commit 905f6b7b authored by chriadam's avatar chriadam

[qtcontacts-sqlite] Store display label group sort order to table manually. Contributes to JB#44742

parent d1af84a5
......@@ -1411,7 +1411,10 @@ static QString buildOrderBy(const QContactSortOrder &order, QStringList *joins,
return QString();
}
QString sortExpression(QStringLiteral("%1.%2").arg(detail.joinToSort ? detail.table : QStringLiteral("Contacts")).arg(field.column));
const bool isDisplayLabelGroup = detail.detailType == QContactDisplayLabel::Type && field.field == QContactDisplayLabel__FieldLabelGroup;
QString sortExpression(QStringLiteral("%1.%2")
.arg(detail.joinToSort ? detail.table : QStringLiteral("Contacts"))
.arg(isDisplayLabelGroup ? QStringLiteral("DisplayLabelGroupSortOrder") : field.column));
bool sortBlanks = true;
bool collate = true;
bool localized = field.fieldType == LocalizedField;
......@@ -1458,7 +1461,7 @@ static QString buildOrderBy(const QContactSortOrder &order, QStringList *joins,
result.append(sortExpression);
if (collate) {
if (!isDisplayLabelGroup && collate) {
if (localized && useLocale) {
result.append(QLatin1String(" COLLATE localeCollation"));
} else {
......@@ -1936,7 +1939,7 @@ QContactManager::Error ContactReader::queryContacts(
QContactManager::Error err = QContactManager::NoError;
const QString idsQueryStatement(QString::fromLatin1(
"SELECT " // Contacts.*, but order can change due to schema upgrades, so list manually.
"SELECT " // order and content can change due to schema upgrades, so list manually.
"Contacts.contactId, "
"Contacts.displayLabel, "
"Contacts.displayLabelGroup, "
......
......@@ -67,7 +67,8 @@ static const char *createContactsTable =
"\n CREATE TABLE Contacts ("
"\n contactId INTEGER PRIMARY KEY ASC AUTOINCREMENT,"
"\n displayLabel TEXT,"
"\n displayLabelGroup TEXT," // Don't specify `COLLATE localeCollation` as a change in locale would be equivalent to a database corruption
"\n displayLabelGroup TEXT,"
"\n displayLabelGroupSortOrder INTEGER,"
"\n firstName TEXT,"
"\n lowerFirstName TEXT,"
"\n lastName TEXT,"
......@@ -1715,6 +1716,24 @@ static bool addDisplayLabelGroup(QSqlDatabase &database)
}
alterQuery.finish();
}
// add the display label group sort order column (precalculated sort index)
{
QSqlQuery alterQuery(database);
const QString statement = QStringLiteral("ALTER TABLE Contacts ADD COLUMN displayLabelGroupSortOrder INTEGER");
if (!alterQuery.prepare(statement)) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to prepare add display label group sort order column query: %1\n%2")
.arg(alterQuery.lastError().text())
.arg(statement));
return false;
}
if (!alterQuery.exec()) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to add display label group sort order column: %1\n%2")
.arg(alterQuery.lastError().text())
.arg(statement));
return false;
}
alterQuery.finish();
}
return true;
}
......@@ -1844,6 +1863,7 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
// for every single contact in our database, read the data required to generate the display label group data.
QVariantList contactIds;
QVariantList displayLabelGroups;
QVariantList displayLabelGroupSortOrders;
{
QSqlQuery selectQuery(database);
selectQuery.setForwardOnly(true);
......@@ -1876,7 +1896,9 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
c.saveDetail(&n);
c.saveDetail(&dl);
displayLabelGroups.append(cdb->determineDisplayLabelGroup(c));
const QString dlg = cdb->determineDisplayLabelGroup(c);
displayLabelGroups.append(dlg);
displayLabelGroupSortOrders.append(cdb->possibleDisplayLabelGroups().indexOf(dlg) + 1);
}
selectQuery.finish();
}
......@@ -1886,10 +1908,11 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
{
for (int i = 0; i < displayLabelGroups.size(); i += 167) {
const QVariantList groups = displayLabelGroups.mid(i, qMin(displayLabelGroups.size() - i, 167));
const QVariantList sortorders = displayLabelGroupSortOrders.mid(i, qMin(displayLabelGroups.size() - i, 167));
const QVariantList ids = contactIds.mid(i, qMin(displayLabelGroups.size() - i, 167));
QSqlQuery updateQuery(database);
const QString statement = QStringLiteral("UPDATE Contacts SET displayLabelGroup = ? WHERE contactId = ?");
const QString statement = QStringLiteral("UPDATE Contacts SET displayLabelGroup = ?, displayLabelGroupSortOrder = ? WHERE contactId = ?");
if (!updateQuery.prepare(statement)) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to prepare update display label groups query: %1\n%2")
.arg(updateQuery.lastError().text())
......@@ -1897,6 +1920,7 @@ static bool executeDisplayLabelGroupLocalizationStatements(QSqlDatabase &databas
return false;
}
updateQuery.addBindValue(groups);
updateQuery.addBindValue(sortorders);
updateQuery.addBindValue(ids);
if (!updateQuery.execBatch()) {
QTCONTACTS_SQLITE_WARNING(QString::fromLatin1("Failed to update display label groups: %1\n%2")
......@@ -2743,6 +2767,22 @@ bool ContactsDatabase::open(const QString &connectionName, bool nonprivileged, b
}
}
m_dlgGenerators.append(m_defaultGenerator.data());
// and build a "superlist" of possible display label groups
// which defines a total sort ordering for display label groups.
const QLocale locale;
for (auto generator : m_dlgGenerators) {
if (generator->validForLocale(locale)) {
const QStringList groups = generator->displayLabelGroups();
for (const QString &group : groups) {
if (!m_possibleDisplayLabelGroups.contains(group)) {
m_possibleDisplayLabelGroups.append(group);
}
}
}
}
m_possibleDisplayLabelGroups.removeAll(QStringLiteral("#"));
m_possibleDisplayLabelGroups.append(QStringLiteral("#"));
}
if (m_database.isOpen()) {
......@@ -3323,6 +3363,11 @@ QStringList ContactsDatabase::displayLabelGroups() const
return groups;
}
QStringList ContactsDatabase::possibleDisplayLabelGroups() const
{
return m_possibleDisplayLabelGroups;
}
#include "../extensions/qcontactdeactivated_impl.h"
#include "../extensions/qcontactincidental_impl.h"
#include "../extensions/qcontactoriginmetadata_impl.h"
......
......@@ -154,6 +154,7 @@ public:
QString determineDisplayLabelGroup(const QContact &c) const;
QStringList displayLabelGroups() const;
QStringList possibleDisplayLabelGroups() const;
static bool execute(QSqlQuery &query);
static bool executeBatch(QSqlQuery &query, QSqlQuery::BatchExecutionMode mode = QSqlQuery::ValuesAsRows);
......@@ -179,6 +180,7 @@ private:
QHash<QString, QSqlQuery> m_preparedQueries;
QVector<QtContactsSqliteExtensions::DisplayLabelGroupGenerator*> m_dlgGenerators;
QScopedPointer<QtContactsSqliteExtensions::DisplayLabelGroupGenerator> m_defaultGenerator;
QStringList m_possibleDisplayLabelGroups;
};
#endif
......@@ -5542,6 +5542,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" INSERT INTO Contacts ("
" displayLabel,"
" displayLabelGroup,"
" displayLabelGroupSortOrder,"
" firstName,"
" lowerFirstName,"
" lastName,"
......@@ -5564,6 +5565,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" VALUES ("
" :displayLabel,"
" :displayLabelGroup,"
" :displayLabelGroupSortOrder,"
" :firstName,"
" :lowerFirstName,"
" :lastName,"
......@@ -5588,6 +5590,7 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
" UPDATE Contacts SET"
" displayLabel = :displayLabel,"
" displayLabelGroup = :displayLabelGroup,"
" displayLabelGroupSortOrder = :displayLabelGroupSortOrder,"
" firstName = :firstName,"
" lowerFirstName = :lowerFirstName,"
" lastName = :lastName,"
......@@ -5620,29 +5623,32 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
QContactDisplayLabel label = contact.detail<QContactDisplayLabel>();
const QString displayLabel = label.label().trimmed();
query.bindValue(0, displayLabel);
query.bindValue(1, m_database.determineDisplayLabelGroup(contact));
query.bindValue(2, firstName);
query.bindValue(3, firstName.toLower());
query.bindValue(4, lastName);
query.bindValue(5, lastName.toLower());
query.bindValue(6, name.value<QString>(QContactName::FieldMiddleName).trimmed());
query.bindValue(7, name.value<QString>(QContactName::FieldPrefix).trimmed());
query.bindValue(8, name.value<QString>(QContactName::FieldSuffix).trimmed());
query.bindValue(9, name.value<QString>(QContactName__FieldCustomLabel).trimmed());
const QString displayLabelGroup = m_database.determineDisplayLabelGroup(contact);
query.bindValue(1, displayLabelGroup);
const int displayLabelGroupSortOrder = m_database.possibleDisplayLabelGroups().indexOf(displayLabelGroup) + 1;
query.bindValue(2, displayLabelGroupSortOrder);
query.bindValue(3, firstName);
query.bindValue(4, firstName.toLower());
query.bindValue(5, lastName);
query.bindValue(6, lastName.toLower());
query.bindValue(7, name.value<QString>(QContactName::FieldMiddleName).trimmed());
query.bindValue(8, name.value<QString>(QContactName::FieldPrefix).trimmed());
query.bindValue(9, name.value<QString>(QContactName::FieldSuffix).trimmed());
query.bindValue(10, name.value<QString>(QContactName__FieldCustomLabel).trimmed());
const QString syncTarget(contact.detail<QContactSyncTarget>().syncTarget());
query.bindValue(10, syncTarget);
query.bindValue(11, syncTarget);
const QContactTimestamp timestamp = contact.detail<QContactTimestamp>();
query.bindValue(11, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldCreationTimestamp).toUTC()));
query.bindValue(12, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldModificationTimestamp).toUTC()));
query.bindValue(12, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldCreationTimestamp).toUTC()));
query.bindValue(13, ContactsDatabase::dateTimeString(timestamp.value<QDateTime>(QContactTimestamp::FieldModificationTimestamp).toUTC()));
const QContactGender gender = contact.detail<QContactGender>();
query.bindValue(13, QString::number(static_cast<int>(gender.gender())));
query.bindValue(14, QString::number(static_cast<int>(gender.gender())));
const QContactFavorite favorite = contact.detail<QContactFavorite>();
query.bindValue(14, favorite.isFavorite());
query.bindValue(15, favorite.isFavorite());
// Does this contact contain the information needed to update hasPhoneNumber?
bool hasPhoneNumberKnown = definitionMask.isEmpty() || detailListContains<QContactPhoneNumber>(definitionMask);
......@@ -5677,26 +5683,26 @@ ContactsDatabase::Query ContactWriter::bindContactDetails(const QContact &contac
}
if (update) {
query.bindValue(15, hasPhoneNumberKnown);
query.bindValue(16, hasPhoneNumber);
query.bindValue(17, hasEmailAddressKnown);
query.bindValue(18, hasEmailAddress);
query.bindValue(19, hasOnlineAccountKnown);
query.bindValue(20, hasOnlineAccount);
query.bindValue(21, isOnlineKnown);
query.bindValue(22, isOnline);
query.bindValue(23, isDeactivatedKnown);
query.bindValue(24, isDeactivated);
query.bindValue(25, contactId);
query.bindValue(16, hasPhoneNumberKnown);
query.bindValue(17, hasPhoneNumber);
query.bindValue(18, hasEmailAddressKnown);
query.bindValue(19, hasEmailAddress);
query.bindValue(20, hasOnlineAccountKnown);
query.bindValue(21, hasOnlineAccount);
query.bindValue(22, isOnlineKnown);
query.bindValue(23, isOnline);
query.bindValue(24, isDeactivatedKnown);
query.bindValue(25, isDeactivated);
query.bindValue(26, contactId);
} else {
query.bindValue(15, hasPhoneNumber);
query.bindValue(16, hasEmailAddress);
query.bindValue(17, hasOnlineAccount);
query.bindValue(18, isOnline);
query.bindValue(19, isDeactivated);
query.bindValue(16, hasPhoneNumber);
query.bindValue(17, hasEmailAddress);
query.bindValue(18, hasOnlineAccount);
query.bindValue(19, isOnline);
query.bindValue(20, isDeactivated);
// Incidental state only applies to creation
query.bindValue(20, !contact.details<QContactIncidental>().isEmpty());
query.bindValue(21, !contact.details<QContactIncidental>().isEmpty());
}
return query;
......
......@@ -238,8 +238,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
// fixup for potential ambiguity in sort order. 3, 7 and 9 all sort equally.
actualOrder.replace(QChar('7'), QChar('3'));
actualOrder.replace(QChar('9'), QChar('3'));
QCOMPARE(actualOrder, QStringLiteral("158233346"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824333"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));
// Now sort by display label group followed by last name.
// We expect the same sorting as display-group-only sorting,
......@@ -259,8 +259,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
// fixup for potential ambiguity in sort order. 3 and 9 sort equally.
actualOrder.replace(QChar('9'), QChar('3'));
QCOMPARE(actualOrder, QStringLiteral("158233746"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824337"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));
// Now sort by display label group followed by first name.
// We expect the same sorting as display-group-only sorting,
......@@ -278,8 +278,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
actualGroups += c.detail<QContactDisplayLabel>().value(QContactDisplayLabel__FieldLabelGroup).toString();
}
QCOMPARE(actualOrder, QStringLiteral("158279346"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824793"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));
// Now sort by display label group followed by last name followed by first name.
// We expect the same sorting as display-group-only sorting,
......@@ -295,8 +295,8 @@ void tst_DisplayLabelGroups::testDisplayLabelGroups()
}
actualGroups += c.detail<QContactDisplayLabel>().value(QContactDisplayLabel__FieldLabelGroup).toString();
}
QCOMPARE(actualOrder, QStringLiteral("158293746"));
QCOMPARE(actualGroups, QStringLiteral("1345EEEOZ"));
QCOMPARE(actualOrder, QStringLiteral("615824937"));
QCOMPARE(actualGroups, QStringLiteral("Z1345OEEE"));
}
QTEST_MAIN(tst_DisplayLabelGroups)
......
......@@ -77,8 +77,8 @@ QStringList TestDlgg::displayLabelGroups() const
QStringLiteral("3"),
QStringLiteral("4"),
QStringLiteral("5"),
QStringLiteral("O"), // sort O before E to test DisplayLabelGroupSortOrder semantics
QStringLiteral("E"),
QStringLiteral("O"),
};
return allGroups;
}
......
......@@ -1923,11 +1923,6 @@ void tst_QContactManagerFiltering::sorting_data()
// Note - the current display label algorithm follows that of nemo-qml-plugin-contacts, and does not include prefix
//newMRow("display label insensitive, binary collation", manager) << manager << dldef << dlfld << asc << false << 0 << ci << "bcdefgaijhk" << "efg"; // the display label is synthesized so that A has "Sir" at the start of it (instead of "Aaron").
//newMRow("display label sensitive, binary collation", manager) << manager << dldef << dlfld << asc << false << 0 << cs << "bcdefgaikjh" << "efg";
#ifdef DISPLAY_LABEL_GROUP_STORAGE_SUPPORTED
FieldIdentifier dlgfld = QContactDisplayLabel__FieldLabelGroup;
newMRow("display label group descending, locale collation", manager) << manager << dldef << dlgfld << asc << false << 0 << cs << "abcdefghijk" << "hijk";
#endif
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment