From 9ded8af8cda134da3cb078a570ab8efe88c88f0b Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Fri, 30 Oct 2015 14:16:04 +1000 Subject: [PATCH] [libcontacts] Provide decomposeDisplayLabel() function. Contributes to MER#1379 Some data sources provide a display label (or formatted name) but not structured name data. The qtcontacts-sqlite backend uses structured name data to perform aggregation, and thus it is useful to have the decomposition function provided for clients (e.g., sync plugins). Contributes to MER#1379 --- libcontacts.pro | 2 +- rpm/libcontacts-qt5.spec | 19 ++++++++++- src/seasidecache.cpp | 61 +++++++++++++++++++++++++++++++++++ src/seasidecache.h | 2 ++ translations/translations.pro | 28 ++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 translations/translations.pro diff --git a/libcontacts.pro b/libcontacts.pro index 267ac44..bc178f4 100644 --- a/libcontacts.pro +++ b/libcontacts.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -SUBDIRS = src tests +SUBDIRS = src tests translations OTHER_FILES += rpm/libcontacts-qt5.spec tests.depends = src diff --git a/rpm/libcontacts-qt5.spec b/rpm/libcontacts-qt5.spec index ca94622..04cd40a 100644 --- a/rpm/libcontacts-qt5.spec +++ b/rpm/libcontacts-qt5.spec @@ -15,6 +15,8 @@ BuildRequires: pkgconfig(mlite5) BuildRequires: pkgconfig(mlocale5) BuildRequires: pkgconfig(mce) BuildRequires: pkgconfig(qtcontacts-sqlite-qt5-extensions) >= 0.2.1 +BuildRequires: qt5-qttools +BuildRequires: qt5-qttools-linguist %description %{summary}. @@ -36,6 +38,20 @@ Requires: %{name} = %{version}-%{release} %description devel %{summary}. + +%package ts-devel +Summary: Translation source for libcontacts +Group: System/Applications + +%description ts-devel +Translation source for libcontacts + +%files ts-devel +%defattr(-,root,root,-) +%{_datadir}/translations/source/libcontacts.ts + + + %prep %setup -q -n %{name}-%{version} @@ -47,7 +63,7 @@ make %{?_smp_mflags} %install rm -rf %{buildroot} -%qmake_install +%qmake5_install %post -p /sbin/ldconfig @@ -56,6 +72,7 @@ rm -rf %{buildroot} %files %defattr(-,root,root,-) %{_libdir}/libcontactcache-qt5.so* +%{_datadir}/translations/libcontacts_eng_en.qm %files tests %defattr(-,root,root,-) diff --git a/src/seasidecache.cpp b/src/seasidecache.cpp index 427bb29..483bd9f 100644 --- a/src/seasidecache.cpp +++ b/src/seasidecache.cpp @@ -1192,6 +1192,67 @@ static bool needsSpaceBetweenNames(const QString &first, const QString &second) || second[0].script() != QChar::Script_Han; } +template +void updateNameDetail(F1 getter, F2 setter, QContactName *nameDetail, const QString &value) +{ + QString existing((nameDetail->*getter)()); + if (!existing.isEmpty()) { + existing.append(QChar::fromLatin1(' ')); + } + (nameDetail->*setter)(existing + value); +} + +void SeasideCache::decomposeDisplayLabel(const QString &formattedDisplayLabel, QContactName *nameDetail) +{ + // Try to parse the structure from the formatted name + // TODO: Use MBreakIterator for localized splitting + QStringList tokens(formattedDisplayLabel.split(QChar::fromLatin1(' '), QString::SkipEmptyParts)); + if (tokens.count() >= 2) { + QString format; + if (tokens.count() == 2) { + //: Format string for allocating 2 tokens to name parts - 2 characters from the set [FMLPS] + //% "FL" + format = qtTrId("libcontacts_name_structure_2_tokens"); + } else if (tokens.count() == 3) { + //: Format string for allocating 3 tokens to name parts - 3 characters from the set [FMLPS] + //% "FML" + format = qtTrId("libcontacts_name_structure_3_tokens"); + } else if (tokens.count() > 3) { + //: Format string for allocating 4 tokens to name parts - 4 characters from the set [FMLPS] + //% "FFML" + format = qtTrId("libcontacts_name_structure_4_tokens"); + + // Coalesce the leading tokens together to limit the possibilities + int excess = tokens.count() - 4; + if (excess > 0) { + QString first(tokens.takeFirst()); + while (--excess >= 0) { + QString nextNamePart = tokens.takeFirst(); + first += (needsSpaceBetweenNames(first, nextNamePart) ? QChar::fromLatin1(' ') : QString()) + nextNamePart; + } + tokens.prepend(first); + } + } + + if (format.length() != tokens.length()) { + qWarning() << "Invalid structure format for" << tokens.count() << "tokens:" << format; + } else { + foreach (const QChar &part, format) { + const QString token(tokens.takeFirst()); + switch (part.toUpper().toLatin1()) { + case 'F': updateNameDetail(&QContactName::firstName, &QContactName::setFirstName, nameDetail, token); break; + case 'M': updateNameDetail(&QContactName::middleName, &QContactName::setMiddleName, nameDetail, token); break; + case 'L': updateNameDetail(&QContactName::lastName, &QContactName::setLastName, nameDetail, token); break; + case 'P': updateNameDetail(&QContactName::prefix, &QContactName::setPrefix, nameDetail, token); break; + case 'S': updateNameDetail(&QContactName::suffix, &QContactName::setSuffix, nameDetail, token); break; + default: + qWarning() << "Invalid structure format character:" << part; + } + } + } + } +} + // small helper to avoid inconvenience QString SeasideCache::generateDisplayLabel(const QContact &contact, DisplayLabelOrder order) { diff --git a/src/seasidecache.h b/src/seasidecache.h index 59741ab..9be3ea6 100644 --- a/src/seasidecache.h +++ b/src/seasidecache.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -323,6 +324,7 @@ class CONTACTCACHE_EXPORT SeasideCache : public QObject static QString primaryName(const QString &firstName, const QString &lastName); static QString secondaryName(const QString &firstName, const QString &lastName); + static void decomposeDisplayLabel(const QString &formattedDisplayLabel, QContactName *nameDetail); static QString generateDisplayLabel(const QContact &contact, DisplayLabelOrder order = FirstNameFirst); static QString generateDisplayLabelFromNonNameDetails(const QContact &contact); static QUrl filteredAvatarUrl(const QContact &contact, const QStringList &metadataFragments = QStringList()); diff --git a/translations/translations.pro b/translations/translations.pro new file mode 100644 index 0000000..6c030ee --- /dev/null +++ b/translations/translations.pro @@ -0,0 +1,28 @@ +TEMPLATE = aux + +TS_FILE = $$OUT_PWD/libcontacts.ts +EE_QM = $$OUT_PWD/libcontacts_eng_en.qm + +ts.commands += lupdate $$PWD/../src -ts $$TS_FILE +ts.output = $$TS_FILE +ts.input = . + +ts_install.files = $$TS_FILE +ts_install.path = $$PREFIX/share/translations/source +ts_install.CONFIG += no_check_exist + +engineering_english.commands += lrelease -idbased $$TS_FILE -qm $$EE_QM +engineering_english.depends = ts +engineering_english.input = $$TS_FILE +engineering_english.output = $$EE_QM + +TRANSLATIONS_PATH = $$PREFIX/share/translations +engineering_english_install.path = $$TRANSLATIONS_PATH +engineering_english_install.files = $$EE_QM +engineering_english_install.CONFIG += no_check_exist + +QMAKE_EXTRA_TARGETS += ts engineering_english +PRE_TARGETDEPS += ts engineering_english +DEFINES += TRANSLATIONS_PATH=\"\\\"\"$${TRANSLATIONS_PATH}\"\\\"\" + +INSTALLS += ts_install engineering_english_install