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:
parent
6316a681f3
commit
c17563eca8
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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(); }
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user