Fix several issues in QCollator

Refactor the code and move more things into the cross platform
code path.

Make sure the flags survive changing the locale of QCollator.
Use the correct locale on Windows, WinRT and OS X. We now
pass all QCollator autotests on these platforms.

Task-number: QTBUG-40778
Change-Id: Ic2d3334b5018c323a35a3ea8fc1d7ab5f99b4e62
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Lars Knoll 2014-08-27 12:57:14 +02:00
parent 6316a681f3
commit c17563eca8
8 changed files with 238 additions and 240 deletions

View File

@ -166,10 +166,12 @@ void QCollator::detach()
*/
void QCollator::setLocale(const QLocale &locale)
{
if (locale == d->locale)
return;
detach();
d->clear();
d->locale = locale;
d->init();
d->dirty = true;
}
/*!
@ -187,6 +189,15 @@ QLocale QCollator::locale() const
\sa caseSensitivity()
*/
void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
if (d->caseSensitivity == cs)
return;
detach();
d->caseSensitivity = cs;
d->dirty = true;
}
/*!
\fn Qt::CaseSensitivity QCollator::caseSensitivity() const
@ -195,6 +206,10 @@ QLocale QCollator::locale() const
\sa setCaseSensitivity()
*/
Qt::CaseSensitivity QCollator::caseSensitivity() const
{
return d->caseSensitivity;
}
/*!
\fn void QCollator::setNumericMode(bool on)
@ -212,6 +227,15 @@ QLocale QCollator::locale() const
\sa numericMode()
*/
void QCollator::setNumericMode(bool on)
{
if (d->numericMode == on)
return;
detach();
d->numericMode = on;
d->dirty = true;
}
/*!
\fn bool QCollator::numericMode() const
@ -220,6 +244,10 @@ QLocale QCollator::locale() const
\sa setNumericMode()
*/
bool QCollator::numericMode() const
{
return d->numericMode;
}
/*!
\fn void QCollator::setIgnorePunctuation(bool on)
@ -230,6 +258,15 @@ QLocale QCollator::locale() const
\sa ignorePunctuation()
*/
void QCollator::setIgnorePunctuation(bool on)
{
if (d->ignorePunctuation == on)
return;
detach();
d->ignorePunctuation = on;
d->dirty = true;
}
/*!
\fn bool QCollator::ignorePunctuation() const
@ -238,6 +275,10 @@ QLocale QCollator::locale() const
\sa setIgnorePunctuation()
*/
bool QCollator::ignorePunctuation() const
{
return d->ignorePunctuation;
}
/*!
\fn int QCollator::compare(const QString &s1, const QString &s2) const

View File

@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE
void QCollatorPrivate::init()
{
cleanup();
UErrorCode status = U_ZERO_ERROR;
QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLatin1();
collator = ucol_open(name.constData(), &status);
@ -63,17 +65,6 @@ void QCollatorPrivate::init()
// enable normalization by default
ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
}
void QCollatorPrivate::cleanup()
{
if (collator)
ucol_close(collator);
}
void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
detach();
// The strength attribute in ICU is rather badly documented. Basically UCOL_PRIMARY
// ignores differences between base characters and accented characters as well as case.
@ -82,55 +73,38 @@ void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
// and does case sensitive comparison.
// UCOL_QUATERNARY is used as default in a few languages such as Japanese to take care of some
// additional differences in those languages.
UColAttributeValue val = (cs == Qt::CaseSensitive) ? UCOL_DEFAULT_STRENGTH : UCOL_SECONDARY;
UColAttributeValue val = (caseSensitivity == Qt::CaseSensitive) ? UCOL_DEFAULT_STRENGTH : UCOL_SECONDARY;
UErrorCode status = U_ZERO_ERROR;
ucol_setAttribute(d->collator, UCOL_STRENGTH, val, &status);
status = U_ZERO_ERROR;
ucol_setAttribute(collator, UCOL_STRENGTH, val, &status);
if (U_FAILURE(status))
qWarning("ucol_setAttribute: Case First failed: %d", status);
}
Qt::CaseSensitivity QCollator::caseSensitivity() const
{
UErrorCode status = U_ZERO_ERROR;
UColAttributeValue attribute = ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status);
return (attribute == UCOL_OFF) ? Qt::CaseInsensitive : Qt::CaseSensitive;
}
void QCollator::setNumericMode(bool on)
{
detach();
UErrorCode status = U_ZERO_ERROR;
ucol_setAttribute(d->collator, UCOL_NUMERIC_COLLATION, on ? UCOL_ON : UCOL_OFF, &status);
status = U_ZERO_ERROR;
ucol_setAttribute(collator, UCOL_NUMERIC_COLLATION, numericMode ? UCOL_ON : UCOL_OFF, &status);
if (U_FAILURE(status))
qWarning("ucol_setAttribute: numeric collation failed: %d", status);
}
bool QCollator::numericMode() const
{
UErrorCode status;
return ucol_getAttribute(d->collator, UCOL_NUMERIC_COLLATION, &status) == UCOL_ON;
}
void QCollator::setIgnorePunctuation(bool on)
{
detach();
UErrorCode status;
ucol_setAttribute(d->collator, UCOL_ALTERNATE_HANDLING, on ? UCOL_SHIFTED : UCOL_NON_IGNORABLE, &status);
status = U_ZERO_ERROR;
ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING, ignorePunctuation ? UCOL_SHIFTED : UCOL_NON_IGNORABLE, &status);
if (U_FAILURE(status))
qWarning("ucol_setAttribute: Alternate handling failed: %d", status);
dirty = false;
}
bool QCollator::ignorePunctuation() const
void QCollatorPrivate::cleanup()
{
UErrorCode status;
return ucol_getAttribute(d->collator, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED;
if (collator)
ucol_close(collator);
collator = 0;
}
int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
{
if (d->dirty)
d->init();
return ucol_strcoll(d->collator, (const UChar *)s1, len1, (const UChar *)s2, len2);
}
@ -146,6 +120,9 @@ int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
QCollatorSortKey QCollator::sortKey(const QString &string) const
{
if (d->dirty)
d->init();
QByteArray result(16 + string.size() + (string.size() >> 2), Qt::Uninitialized);
int size = ucol_getSortKey(d->collator, (const UChar *)string.constData(),
string.size(), (uint8_t *)result.data(), result.size());

View File

@ -55,85 +55,50 @@ void QCollatorPrivate::init()
{
cleanup();
LocaleRef localeRef;
int rc = LocaleRefFromLocaleString(locale.name().toLocal8Bit(), &localeRef);
int rc = LocaleRefFromLocaleString(locale.bcp47Name().toLocal8Bit(), &localeRef);
if (rc != 0)
qWarning() << "couldn't initialize the locale";
UInt32 options = 0;
if (caseSensitivity == Qt::CaseInsensitive)
options |= kUCCollateCaseInsensitiveMask;
if (numericMode)
options |= kUCCollateDigitsAsNumberMask;
if (ignorePunctuation)
options |= kUCCollatePunctuationSignificantMask;
OSStatus status = UCCreateCollator(
localeRef,
0,
collator.options,
&collator.collator
options,
&collator
);
if (status != 0)
qWarning() << "Couldn't initialize the collator";
dirty = false;
}
void QCollatorPrivate::cleanup()
{
UCDisposeCollator(&collator.collator);
collator.collator = 0;
}
void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
detach();
if (cs == Qt::CaseSensitive)
d->collator.options &= ~kUCCollateCaseInsensitiveMask;
else
d->collator.options |= kUCCollateCaseInsensitiveMask;
d->init();
}
Qt::CaseSensitivity QCollator::caseSensitivity() const
{
return !(d->collator.options & kUCCollateCaseInsensitiveMask) ? Qt::CaseInsensitive : Qt::CaseSensitive;
}
void QCollator::setNumericMode(bool on)
{
detach();
if (on)
d->collator.options |= kUCCollateDigitsAsNumberMask;
else
d->collator.options &= ~kUCCollateDigitsAsNumberMask;
d->init();
}
bool QCollator::numericMode() const
{
return bool(d->collator.options & kUCCollateDigitsAsNumberMask);
}
void QCollator::setIgnorePunctuation(bool on)
{
detach();
if (on)
d->collator.options |= kUCCollatePunctuationSignificantMask;
else
d->collator.options &= ~kUCCollatePunctuationSignificantMask;
d->init();
}
bool QCollator::ignorePunctuation() const
{
return bool(d->collator.options & kUCCollatePunctuationSignificantMask);
if (collator)
UCDisposeCollator(&collator);
collator = 0;
}
int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
{
if (d->dirty)
d->init();
SInt32 result;
Boolean equivalent;
UCCompareText(d->collator.collator,
reinterpret_cast<const UniChar *>(s1), len1,
reinterpret_cast<const UniChar *>(s2), len2,
&equivalent,
&result);
UCCompareText(d->collator,
reinterpret_cast<const UniChar *>(s1), len1,
reinterpret_cast<const UniChar *>(s2), len2,
&equivalent,
&result);
if (equivalent)
return 0;
return result < 0 ? -1 : 1;
@ -150,15 +115,18 @@ int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
QCollatorSortKey QCollator::sortKey(const QString &string) const
{
if (d->dirty)
d->init();
//Documentation recommends having it 5 times as big as the input
QVector<UCCollationValue> ret(string.size() * 5);
ItemCount actualSize;
int status = UCGetCollationKey(d->collator.collator, reinterpret_cast<const UniChar *>(string.constData()), string.count(),
int status = UCGetCollationKey(d->collator, reinterpret_cast<const UniChar *>(string.constData()), string.count(),
ret.size(), &actualSize, ret.data());
ret.resize(actualSize+1);
if (status == kUCOutputBufferTooSmall) {
UCGetCollationKey(d->collator.collator, reinterpret_cast<const UniChar *>(string.constData()), string.count(),
UCGetCollationKey(d->collator, reinterpret_cast<const UniChar *>(string.constData()), string.count(),
ret.size(), &actualSize, ret.data());
}
ret[actualSize] = 0;

View File

@ -49,6 +49,8 @@
#include <unicode/ucol.h>
#elif defined(Q_OS_OSX)
#include <CoreServices/CoreServices.h>
#elif defined(Q_OS_WIN)
#include <qt_windows.h>
#endif
QT_BEGIN_NAMESPACE
@ -58,17 +60,16 @@ typedef UCollator *CollatorType;
typedef QByteArray CollatorKeyType;
#elif defined(Q_OS_OSX)
typedef CollatorRef CollatorType;
typedef QVector<UCCollationValue> CollatorKeyType;
struct CollatorType {
CollatorType(int opt) : collator(NULL), options(opt) {}
CollatorRef collator;
UInt32 options;
};
#elif defined(Q_OS_WIN)
typedef QString CollatorKeyType;
typedef int CollatorType;
# ifdef Q_OS_WINRT
# define USE_COMPARESTRINGEX
# endif
#else //posix
typedef QVector<wchar_t> CollatorKeyType;
typedef int CollatorType;
@ -79,6 +80,17 @@ class Q_CORE_EXPORT QCollatorPrivate
public:
QAtomicInt ref;
QLocale locale;
#if defined(Q_OS_WIN)
#ifdef USE_COMPARESTRINGEX
QString localeName;
#else
LCID localeID;
#endif
#endif
Qt::CaseSensitivity caseSensitivity;
bool numericMode;
bool ignorePunctuation;
bool dirty;
CollatorType collator;
@ -91,7 +103,12 @@ public:
void cleanup();
QCollatorPrivate()
: ref(1), collator(0)
: ref(1),
caseSensitivity(Qt::CaseSensitive),
numericMode(false),
ignorePunctuation(false),
dirty(true),
collator(0)
{ cleanup(); }
~QCollatorPrivate() { cleanup(); }

View File

@ -50,47 +50,21 @@ QT_BEGIN_NAMESPACE
void QCollatorPrivate::init()
{
if (locale != QLocale())
qWarning("Only default locale supported with the posix collation implementation");
if (caseSensitivity != Qt::CaseSensitive)
qWarning("Case insensitive sorting unsupported in the posix collation implementation");
if (numericMode)
qWarning("Numeric mode unsupported in the posix collation implementation");
if (ignorePunctuation)
qWarning("Ignoring punctuation unsupported in the posix collation implementation");
dirty = false;
}
void QCollatorPrivate::cleanup()
{
}
void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
Q_UNUSED(cs);
qWarning("unsupported in the posix collation implementation");
}
Qt::CaseSensitivity QCollator::caseSensitivity() const
{
qWarning("unsupported in the posix collation implementation");
return Qt::CaseSensitive;
}
void QCollator::setNumericMode(bool on)
{
Q_UNUSED(on);
qWarning("unsupported in the posix collation implementation");
}
bool QCollator::numericMode() const
{
return true;
}
void QCollator::setIgnorePunctuation(bool on)
{
Q_UNUSED(on);
qWarning("unsupported in the posix collation implementation");
}
bool QCollator::ignorePunctuation() const
{
qWarning("unsupported in the posix collation implementation");
return false;
}
static void stringToWCharArray(QVarLengthArray<wchar_t> &ret, const QString &string)
{
ret.resize(string.length());
@ -112,16 +86,23 @@ int QCollator::compare(const QString &s1, const QString &s2) const
QVarLengthArray<wchar_t> array1, array2;
stringToWCharArray(array1, s1);
stringToWCharArray(array2, s2);
return std::wcscoll(array1.constData(), array2.constData());
int result = std::wcscoll(array1.constData(), array2.constData());
return result > 0 ? 1 : (result == 0 ? 0 : -1);
}
int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
{
if (d->dirty)
d->init();
return compare(s1.constData(), s1.size(), s2.constData(), s2.size());
}
QCollatorSortKey QCollator::sortKey(const QString &string) const
{
if (d->dirty)
d->init();
QVarLengthArray<wchar_t> original;
stringToWCharArray(original, string);
QVector<wchar_t> result(string.size());
@ -137,8 +118,7 @@ QCollatorSortKey QCollator::sortKey(const QString &string) const
int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
{
return std::wcscmp(d->m_key.constData(),
otherKey.d->m_key.constData());
return std::wcscmp(d->m_key.constData(), otherKey.d->m_key.constData());
}
QT_END_NAMESPACE

View File

@ -50,90 +50,64 @@
QT_BEGIN_NAMESPACE
//NOTE: SORT_DIGITSASNUMBERS is available since win7
#ifndef SORT_DIGITSASNUMBERS
#define SORT_DIGITSASNUMBERS 8
#endif
// implemented in qlocale_win.cpp
extern LCID qt_inIsoNametoLCID(const char *name);
void QCollatorPrivate::init()
{
collator = 0;
#ifndef USE_COMPARESTRINGEX
localeID = qt_inIsoNametoLCID(locale.bcp47Name().toUtf8().constData());
#else
localeName = locale.bcp47Name();
#endif
if (caseSensitivity == Qt::CaseInsensitive)
collator |= NORM_IGNORECASE;
if (numericMode) {
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7)
collator |= SORT_DIGITSASNUMBERS;
else
qWarning() << "Numeric sorting unsupported on Windows versions older than Windows 7.";
}
if (ignorePunctuation)
collator |= NORM_IGNORESYMBOLS;
dirty = false;
}
void QCollatorPrivate::cleanup()
{
}
void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
detach();
if (cs == Qt::CaseSensitive)
d->collator &= ~NORM_IGNORECASE;
else
d->collator |= NORM_IGNORECASE;
}
Qt::CaseSensitivity QCollator::caseSensitivity() const
{
return d->collator & NORM_IGNORECASE ? Qt::CaseInsensitive : Qt::CaseSensitive;
}
//NOTE: SORT_DIGITSASNUMBERS is available since win7
#ifndef SORT_DIGITSASNUMBERS
#define SORT_DIGITSASNUMBERS 8
#endif
void QCollator::setNumericMode(bool on)
{
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
detach();
if (on)
d->collator |= SORT_DIGITSASNUMBERS;
else
d->collator &= ~SORT_DIGITSASNUMBERS;
} else {
Q_UNUSED(on);
qWarning() << "unsupported in the win collation implementation";
}
}
bool QCollator::numericMode() const
{
if (QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7) {
return bool(d->collator & SORT_DIGITSASNUMBERS);
} else {
qWarning() << "unsupported in the win collation implementation";
return false;
}
}
void QCollator::setIgnorePunctuation(bool on)
{
detach();
if (on)
d->collator |= NORM_IGNORESYMBOLS;
else
d->collator &= ~NORM_IGNORESYMBOLS;
}
bool QCollator::ignorePunctuation() const
{
return bool(d->collator & NORM_IGNORESYMBOLS);
}
int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
{
if (d->dirty)
d->init();
//* from Windows documentation *
// Returns one of the following values if successful. To maintain the C runtime convention of
// comparing strings, the value 2 can be subtracted from a nonzero return value. Then, the
// meaning of <0, ==0, and >0 is consistent with the C runtime.
#ifndef Q_OS_WINRT
return CompareString(LOCALE_USER_DEFAULT, d->collator,
#ifndef USE_COMPARESTRINGEX
return CompareString(d->localeID, d->collator,
reinterpret_cast<const wchar_t*>(s1), len1,
reinterpret_cast<const wchar_t*>(s2), len2) - 2;
#else // !Q_OS_WINRT
return CompareStringEx(LOCALE_NAME_USER_DEFAULT, d->collator,
#else
return CompareStringEx(LPCWSTR(d->localeName.utf16()), d->collator,
reinterpret_cast<LPCWSTR>(s1), len1,
reinterpret_cast<LPCWSTR>(s2), len2, NULL, NULL, 0) - 2;
#endif // Q_OS_WINRT
#endif
}
int QCollator::compare(const QString &str1, const QString &str2) const
@ -148,32 +122,29 @@ int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
QCollatorSortKey QCollator::sortKey(const QString &string) const
{
#ifndef Q_OS_WINRT
int size = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | d->collator,
if (d->dirty)
d->init();
#ifndef USE_COMPARESTRINGEX
int size = LCMapStringW(d->localeID, LCMAP_SORTKEY | d->collator,
reinterpret_cast<const wchar_t*>(string.constData()), string.size(),
0, 0);
#elif defined(Q_OS_WINPHONE)
int size = 0;
Q_UNIMPLEMENTED();
Q_UNUSED(string)
#else // Q_OS_WINPHONE
int size = LCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_SORTKEY | d->collator,
#else
int size = LCMapStringEx(LPCWSTR(d->localeName.utf16()), LCMAP_SORTKEY | d->collator,
reinterpret_cast<LPCWSTR>(string.constData()), string.size(),
0, 0, NULL, NULL, 0);
#endif // !Q_OS_WINPHONE
#endif
QString ret(size, Qt::Uninitialized);
#ifndef Q_OS_WINRT
int finalSize = LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_SORTKEY | d->collator,
#ifndef USE_COMPARESTRINGEX
int finalSize = LCMapStringW(d->localeID, LCMAP_SORTKEY | d->collator,
reinterpret_cast<const wchar_t*>(string.constData()), string.size(),
reinterpret_cast<wchar_t*>(ret.data()), ret.size());
#elif defined(Q_OS_WINPHONE)
int finalSize = 0;
#else // Q_OS_WINPHONE
int finalSize = LCMapStringEx(LOCALE_NAME_USER_DEFAULT, LCMAP_SORTKEY | d->collator,
#else
int finalSize = LCMapStringEx(LPCWSTR(d->localeName.utf16()), LCMAP_SORTKEY | d->collator,
reinterpret_cast<LPCWSTR>(string.constData()), string.size(),
reinterpret_cast<LPWSTR>(ret.data()), ret.size(),
NULL, NULL, 0);
#endif // !Q_OS_WINPHONE
#endif
if (finalSize == 0) {
qWarning() << "there were problems when generating the ::sortKey by LCMapStringW with error:" << GetLastError();
}

View File

@ -1012,6 +1012,32 @@ static const char *winLangCodeToIsoName(int code)
}
LCID qt_inIsoNametoLCID(const char *name)
{
// handle norwegian manually, the list above will fail
if (!strncmp(name, "nb", 2))
return 0x0414;
else if (!strncmp(name, "nn", 2))
return 0x0814;
char n[64];
strncpy(n, name, sizeof(n));
n[sizeof(n)-1] = 0;
char *c = n;
while (*c) {
if (*c == '-')
*c = '_';
++c;
}
for (int i = 0; i < windows_to_iso_count; ++i) {
if (!strcmp(n, windows_to_iso_list[i].iso_name))
return windows_to_iso_list[i].windows_code;
}
return LOCALE_USER_DEFAULT;
}
#ifndef Q_OS_WINRT
static QString winIso639LangName(LCID id)
#else

View File

@ -55,6 +55,8 @@ private Q_SLOTS:
void compare_data();
void compare();
void state();
};
#ifdef Q_COMPILER_RVALUE_REFS
@ -121,26 +123,18 @@ void tst_QCollator::compare_data()
diaresis (E4), which comes before o diaresis (F6), which
all come after z.
*/
#if !defined(Q_OS_WIN) || defined(QT_USE_ICU)
QTest::newRow("swedish1") << QString("sv_SE") << QString::fromLatin1("\xe5") << QString::fromLatin1("\xe4") << -1 << -1;
#endif
QTest::newRow("swedish2") << QString("sv_SE") << QString::fromLatin1("\xe4") << QString::fromLatin1("\xf6") << -1 << -1;
QTest::newRow("swedish3") << QString("sv_SE") << QString::fromLatin1("\xe5") << QString::fromLatin1("\xf6") << -1 << -1;
#if !defined(Q_OS_OSX) && (!defined(Q_OS_WIN) || defined(QT_USE_ICU))
QTest::newRow("swedish4") << QString("sv_SE") << QString::fromLatin1("z") << QString::fromLatin1("\xe5") << -1 << -1;
#endif
/*
In Norwegian, ae (E6) comes before o with stroke (D8), which
comes before a with ring above (E5).
*/
QTest::newRow("norwegian1") << QString("no_NO") << QString::fromLatin1("\xe6") << QString::fromLatin1("\xd8") << -1 << -1;
#if !defined(Q_OS_WIN) || defined(QT_USE_ICU)
# ifndef Q_OS_OSX
QTest::newRow("norwegian2") << QString("no_NO") << QString::fromLatin1("\xd8") << QString::fromLatin1("\xe5") << -1 << -1;
# endif
QTest::newRow("norwegian3") << QString("no_NO") << QString::fromLatin1("\xe6") << QString::fromLatin1("\xe5") << -1 << -1;
#endif // !Q_OS_WIN || QT_USE_ICU
/*
In German, z comes *after* a with diaresis (E4),
which comes before o diaresis (F6).
@ -180,6 +174,30 @@ void tst_QCollator::compare()
QCOMPARE(collator.compare(s1, s2), caseInsensitiveResult);
}
void tst_QCollator::state()
{
QCollator c;
c.setCaseSensitivity(Qt::CaseInsensitive);
c.setLocale(QLocale::German);
c.compare(QString("a"), QString("b"));
QCOMPARE(c.caseSensitivity(), Qt::CaseInsensitive);
QCOMPARE(c.locale(), QLocale(QLocale::German));
c.setLocale(QLocale::French);
c.setNumericMode(true);
c.setIgnorePunctuation(true);
c.setLocale(QLocale::Norwegian);
QCOMPARE(c.caseSensitivity(), Qt::CaseInsensitive);
QCOMPARE(c.numericMode(), true);
QCOMPARE(c.ignorePunctuation(), true);
QCOMPARE(c.locale(), QLocale(QLocale::Norwegian));
}
QTEST_APPLESS_MAIN(tst_QCollator)
#include "tst_qcollator.moc"