summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/tools/qcollator.cpp330
-rw-r--r--src/corelib/tools/qcollator.h70
2 files changed, 144 insertions, 256 deletions
diff --git a/src/corelib/tools/qcollator.cpp b/src/corelib/tools/qcollator.cpp
index f41e9d61bf..28d42f4dca 100644
--- a/src/corelib/tools/qcollator.cpp
+++ b/src/corelib/tools/qcollator.cpp
@@ -50,8 +50,6 @@
#include <unicode/ures.h>
#endif
-#include "qdebug.h"
-
QT_BEGIN_NAMESPACE
@@ -60,7 +58,6 @@ class QCollatorPrivate
public:
QAtomicInt ref;
QLocale locale;
- QCollator::Collation collation;
#ifdef QT_USE_ICU
UCollator *collator;
@@ -68,50 +65,48 @@ public:
void *collator;
#endif
- QStringList indexCharacters;
-
void clear() {
#ifdef QT_USE_ICU
if (collator)
ucol_close(collator);
#endif
collator = 0;
- indexCharacters.clear();
}
QCollatorPrivate()
- : collation(QCollator::Default),
+ : ref(1),
collator(0)
- { ref.store(1); }
+ {
+ }
~QCollatorPrivate();
+ void init();
+
private:
Q_DISABLE_COPY(QCollatorPrivate)
};
+class QCollatorSortKeyPrivate : public QSharedData
+{
+ friend class QCollator;
+public:
+ QCollatorSortKeyPrivate(const QByteArray &key) :
+ QSharedData(),
+ m_key(key)
+ {
+ }
+
+ QByteArray m_key;
+
+private:
+ Q_DISABLE_COPY(QCollatorSortKeyPrivate)
+};
QCollatorPrivate::~QCollatorPrivate()
{
clear();
}
-static const int collationStringsCount = 13;
-static const char * const collationStrings[collationStringsCount] = {
- "default",
- "big5han",
- "dictionary",
- "direct",
- "gb2312han",
- "phonebook",
- "pinyin",
- "phonetic",
- "reformed",
- "standard",
- "stroke",
- "traditional",
- "unihan"
-};
-
/*!
\class QCollator
\inmodule QtCore
@@ -138,20 +133,16 @@ static const char * const collationStrings[collationStringsCount] = {
*/
/*!
- Constructs a QCollator from \a locale and \a collation. If \a collation is not
- specified the default collation algorithm for the locale is being used. If
- \a locale is not specified QLocale::default() is being used.
+ Constructs a QCollator from \a locale. If \a locale is not specified QLocale::default()
+ is being used.
- \sa setLocale(), setCollation()
+ \sa setLocale()
*/
-QCollator::QCollator(const QLocale &locale, QCollator::Collation collation)
+QCollator::QCollator(const QLocale &locale)
: d(new QCollatorPrivate)
{
d->locale = locale;
- if ((int)collation >= 0 && (int)collation < collationStringsCount)
- d->collation = collation;
-
- init();
+ d->init();
}
/*!
@@ -190,19 +181,17 @@ QCollator &QCollator::operator=(const QCollator &other)
/*!
\internal
*/
-void QCollator::init()
+void QCollatorPrivate::init()
{
- Q_ASSERT((int)d->collation < collationStringsCount);
#ifdef QT_USE_ICU
- const char *collationString = collationStrings[(int)d->collation];
UErrorCode status = U_ZERO_ERROR;
- QByteArray name = (d->locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')) + QLatin1String("@collation=") + QLatin1String(collationString)).toLatin1();
- d->collator = ucol_open(name.constData(), &status);
+ QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLocal8Bit();
+ collator = ucol_open(name.constData(), &status);
if (U_FAILURE(status))
qWarning("Could not create collator: %d", status);
// enable normalization by default
- ucol_setAttribute(d->collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
#endif
}
@@ -215,8 +204,6 @@ void QCollator::detach()
QCollatorPrivate *x = new QCollatorPrivate;
x->ref.store(1);
x->locale = d->locale;
- x->collation = d->collation;
- x->collator = 0;
if (!d->ref.deref())
delete d;
d = x;
@@ -233,7 +220,7 @@ void QCollator::setLocale(const QLocale &locale)
d->clear();
d->locale = locale;
- init();
+ d->init();
}
/*!
@@ -245,159 +232,36 @@ QLocale QCollator::locale() const
}
/*!
- \enum QCollator::Collation
-
- This enum can be used to specify an alternate collation algorithm to be used instead
- of the default algorithm for the locale.
-
- Possible values are:
-
- \value Default Use the default algorithm for the locale
- \value Big5Han
- \value Dictionary
- \value Direct
- \value GB2312Han
- \value PhoneBook
- \value Pinyin
- \value Phonetic
- \value Reformed
- \value Standard
- \value Stroke
- \value Traditional
- \value UniHan
-*/
-
-/*!
- Sets the \a collation algorithm to be used.
-
- \sa QCollator::Collation
+ Sets the case \a cs of the collator.
*/
-void QCollator::setCollation(QCollator::Collation collation)
-{
- if ((int)collation < 0 || (int)collation >= collationStringsCount)
- return;
-
- if (d->ref.load() != 1)
- detach();
- d->clear();
- d->collation = collation;
-
- init();
-}
-/*!
- Returns the currently used collation algorithm.
-
- \sa QCollator::Collation
- */
-QCollator::Collation QCollator::collation() const
-{
- return d->collation;
-}
-
-/*!
- Returns a unique identifer for this collation object.
-
- This method is helpful to save and restore defined collation
- objects.
-
- \sa fromIdentifier()
- */
-QString QCollator::identifier() const
-{
- QString id = d->locale.bcp47Name();
- if (d->collation != QCollator::Default) {
- id += QLatin1String("@collation=");
- id += QLatin1String(collationStrings[d->collation]);
- }
- // this ensures the ID is compatible with ICU
- id.replace('-', '_');
- return id;
-}
-
-/*!
- Creates a QCollator from a unique \a identifier and returns it.
-
- \sa identifier()
- */
-QCollator QCollator::fromIdentifier(const QString &identifier)
-{
- QString localeString = identifier;
- QString collationString;
- int at = identifier.indexOf(QLatin1Char('@'));
- if (at >= 0) {
- localeString = identifier.left(at);
- collationString = identifier.mid(at + strlen("@collation="));
- }
-
- QLocale locale(localeString);
- Collation collation = Default;
- if (!collationString.isEmpty()) {
- for (int i = 0; i < collationStringsCount; ++i) {
- if (QLatin1String(collationStrings[i]) == collationString) {
- collation = Collation(i);
- break;
- }
- }
- }
- return QCollator(locale, collation);
-}
-
-/*!
- \enum QCollator::CasePreference
-
- This enum can be used to tailor the case preference during collation.
-
- \value CasePreferenceOff No case preference, use what is the standard for the locale
- \value CasePreferenceUpper Sort upper case characters before lower case
- \value CasePreferenceLower Sort lower case characters before upper case
-*/
-
-/*!
- Sets the case \a preference of the collator.
-
- \sa QCollator::CasePreference
- */
-void QCollator::setCasePreference(CasePreference preference)
+void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
{
if (d->ref.load() != 1)
detach();
#ifdef QT_USE_ICU
- UColAttributeValue val = UCOL_OFF;
- if (preference == QCollator::CasePreferenceUpper)
- val = UCOL_UPPER_FIRST;
- else if (preference == QCollator::CasePreferenceLower)
- val = UCOL_LOWER_FIRST;
+ UColAttributeValue val = (cs == Qt::CaseSensitive) ? UCOL_UPPER_FIRST : UCOL_OFF;
UErrorCode status = U_ZERO_ERROR;
ucol_setAttribute(d->collator, UCOL_CASE_FIRST, val, &status);
if (U_FAILURE(status))
qWarning("ucol_setAttribute: Case First failed: %d", status);
#else
- Q_UNUSED(preference);
+ Q_UNUSED(cs);
#endif
}
/*!
Returns case preference of the collator.
-
- \sa QCollator::CasePreference
*/
-QCollator::CasePreference QCollator::casePreference() const
+Qt::CaseSensitivity QCollator::caseSensitivity() const
{
#ifdef QT_USE_ICU
UErrorCode status = U_ZERO_ERROR;
- switch (ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status)) {
- case UCOL_UPPER_FIRST:
- return QCollator::CasePreferenceUpper;
- case UCOL_LOWER_FIRST:
- return QCollator::CasePreferenceLower;
- case UCOL_OFF:
- default:
- break;
- }
+ UColAttributeValue attribute = ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status);
+ return (attribute == UCOL_OFF) ? Qt::CaseInsensitive : Qt::CaseSensitive;
#endif
- return QCollator::CasePreferenceOff;
+ return Qt::CaseSensitive;
}
/*!
@@ -512,16 +376,16 @@ int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) con
}
/*!
- Returns a sortKey for \a string. The sortkey can be used as a placeholder
- for the string that can be then sorted using regular strcmp based sorting.
+ Returns a sortKey for \a string.
- Creating the sort key is usually somewhat slower, then using the compare()
+ Creating the sort key is usually somewhat slower, than using the compare()
methods directly. But if the string is compared repeatedly (e.g. when sorting
a whole list of strings), it's usually faster to create the sort keys for each
string and then sort using the keys.
*/
-QByteArray QCollator::sortKey(const QString &string) const
+QCollatorSortKey QCollator::sortKey(const QString &string) const
{
+ QByteArray key;
#ifdef QT_USE_ICU
QByteArray result(16 + string.size() + (string.size() >> 2), Qt::Uninitialized);
int size = ucol_getSortKey(d->collator, (const UChar *)string.constData(),
@@ -532,63 +396,91 @@ QByteArray QCollator::sortKey(const QString &string) const
string.size(), (uint8_t *)result.data(), result.size());
}
result.truncate(size);
- return result;
+ key = result;
#else
- return string.toLower().toUtf8();
+ key = string.toLatin1();
#endif
+ return QCollatorSortKey(new QCollatorSortKeyPrivate(key));
}
-static QStringList englishIndexCharacters()
+/*!
+ \fn bool QCollator::operator()(const QString &s1, const QString &s2) const
+ \internal
+*/
+
+/*!
+ \class QCollatorSortKey
+ \inmodule QtCore
+ \brief The QCollatorSortKey class can be used to speed up string collation.
+
+ \since 5.2
+
+ The QCollatorSortKey class is always created by QCollator::sortKey()
+ and is used for fast strings collation, for example when collating many strings.
+
+ \reentrant
+ \ingroup i18n
+ \ingroup string-processing
+ \ingroup shared
+
+ \sa QCollator, QCollator::sortKey()
+*/
+
+/*!
+ \internal
+ */
+QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d)
+ : d(d)
{
- QString chars = QString::fromLatin1("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z");
- return chars.split(QLatin1Char(' '), QString::SkipEmptyParts);
}
/*!
- Returns a string list of primary index characters. This is useful when presenting the
- sorted list in a user interface with section headers.
-*/
-QStringList QCollator::indexCharacters() const
+ Constructs a copy of the \a other collator sorting key.
+ */
+QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey& other)
+ : d(other.d)
{
- if (!d->indexCharacters.isEmpty())
- return d->indexCharacters;
+}
-#ifdef QT_USE_ICU
- QByteArray id = identifier().toLatin1();
+/*!
+ Destroys the collator key.
+ */
+QCollatorSortKey::~QCollatorSortKey()
+{
+}
- UErrorCode status = U_ZERO_ERROR;
- UResourceBundle *res = ures_open(NULL, id, &status);
-
- if (U_FAILURE(status)) {
- d->indexCharacters = englishIndexCharacters();
- } else {
-
- qint32 len = 0;
- status = U_ZERO_ERROR;
- const UChar *val = ures_getStringByKey(res, "ExemplarCharactersIndex", &len, &status);
- if (U_FAILURE(status)) {
- d->indexCharacters = englishIndexCharacters();
- } else {
- QString chars(reinterpret_cast<const QChar *>(val), len);
- chars.remove('[');
- chars.remove(']');
- chars.remove('{');
- chars.remove('}');
- d->indexCharacters = chars.split(QLatin1Char(' '), QString::SkipEmptyParts);
- }
+/*!
+ Assigns \a other to this collator key.
+ */
+QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other)
+{
+ if (this != &other) {
+ d = other.d;
}
+ return *this;
+}
- ures_close(res);
-#else
- d->indexCharacters = englishIndexCharacters();
-#endif
+/*!
+ According to the QCollator that created the key, returns true if the
+ key should be sorted before than \a otherKey; otherwise returns false.
- return d->indexCharacters;
+ \sa compare()
+ */
+bool QCollatorSortKey::operator<(const QCollatorSortKey &otherKey) const
+{
+ return d->m_key < otherKey.d->m_key;
}
/*!
- \fn bool QCollator::operator()(const QString &s1, const QString &s2) const
- \internal
-*/
+ Compares the key to \a otherKey. Returns a negative value if the key
+ is less than \a otherKey, 0 if the key is equal to \a otherKey or a
+ positive value if the key is greater than \a otherKey.
+
+ \sa operator<()
+ */
+int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
+{
+ return qstrcmp(d->m_key, otherKey.d->m_key);
+}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcollator.h b/src/corelib/tools/qcollator.h
index 02470c331f..677092c718 100644
--- a/src/corelib/tools/qcollator.h
+++ b/src/corelib/tools/qcollator.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
@@ -39,36 +40,46 @@
**
****************************************************************************/
-#ifndef QCOLLATOR_P_H
-#define QCOLLATOR_P_H
+#ifndef QCOLLATOR_H
+#define QCOLLATOR_H
#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
#include <QtCore/qlocale.h>
QT_BEGIN_NAMESPACE
class QCollatorPrivate;
+class QCollatorSortKeyPrivate;
+
+class Q_CORE_EXPORT QCollatorSortKey
+{
+ friend class QCollator;
+public:
+ QCollatorSortKey(const QCollatorSortKey &other);
+ ~QCollatorSortKey();
+ QCollatorSortKey &operator=(const QCollatorSortKey &other);
+#ifdef Q_COMPILER_RVALUE_REFS
+ QCollatorSortKey &operator=(QCollatorSortKey &&other)
+ { qSwap(d, other.d); return *this; }
+#endif
+
+ bool operator<(const QCollatorSortKey &key) const;
+ int compare(const QCollatorSortKey &key) const;
+
+protected:
+ QCollatorSortKey(QCollatorSortKeyPrivate*);
+
+ QSharedDataPointer<QCollatorSortKeyPrivate> d;
+
+private:
+ QCollatorSortKey();
+};
class Q_CORE_EXPORT QCollator
{
public:
- enum Collation {
- Default,
- Big5Han,
- Dictionary,
- Direct,
- GB2312Han,
- PhoneBook,
- Pinyin,
- Phonetic,
- Reformed,
- Standard,
- Stroke,
- Traditional,
- UniHan
- };
-
- QCollator(const QLocale &locale = QLocale(), QCollator::Collation collation = QCollator::Default);
+ QCollator(const QLocale &locale = QLocale());
QCollator(const QCollator &);
~QCollator();
QCollator &operator=(const QCollator &);
@@ -76,20 +87,8 @@ public:
void setLocale(const QLocale &locale);
QLocale locale() const;
- void setCollation(Collation collation);
- Collation collation() const;
-
- QString identifier() const;
- static QCollator fromIdentifier(const QString &identifier);
-
- enum CasePreference {
- CasePreferenceOff = 0x0,
- CasePreferenceUpper = 0x1,
- CasePreferenceLower = 0x2
- };
-
- CasePreference casePreference() const;
- void setCasePreference(CasePreference preference);
+ Qt::CaseSensitivity caseSensitivity() const;
+ void setCaseSensitivity(Qt::CaseSensitivity cs);
void setNumericMode(bool on);
bool numericMode() const;
@@ -104,15 +103,12 @@ public:
bool operator()(const QString &s1, const QString &s2) const
{ return compare(s1, s2) < 0; }
- QByteArray sortKey(const QString &string) const;
-
- QStringList indexCharacters() const;
+ QCollatorSortKey sortKey(const QString &string) const;
private:
QCollatorPrivate *d;
void detach();
- void init();
};
QT_END_NAMESPACE