1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtCore module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include "qcollator_p.h"
43
#include "qstringlist.h"
47
#include <unicode/utypes.h>
48
#include <unicode/ucol.h>
49
#include <unicode/ustring.h>
50
#include <unicode/ures.h>
58
class QCollatorPrivate
63
QCollator::Collation collation;
71
QStringList indexCharacters;
79
indexCharacters.clear();
83
: collation(QCollator::Default),
89
Q_DISABLE_COPY(QCollatorPrivate)
93
QCollatorPrivate::~QCollatorPrivate()
98
static const int collationStringsCount = 13;
99
static const char * const collationStrings[collationStringsCount] = {
118
\brief The QCollator class compares strings according to a localized collation algorithm.
124
\ingroup string-processing
127
QCollator is initialized with a QLocale and an optional collation strategy. It tries to
128
initialize the collator with the specified values. The collator can then be used to compare
129
and sort strings in a locale dependent fashion.
131
A QCollator object can be used together with template based sorting algorithms such as std::sort
132
to sort a list of QStrings.
134
In addition to the locale and collation strategy, several optional flags can be set that influence
135
the result of the collation.
139
Constructs a QCollator from \a locale and \a collation. If \a collation is not
140
specified the default collation algorithm for the locale is being used. If
141
\a locale is not specified QLocale::default() is being used.
143
\sa setLocale, setCollation, setOptions
145
QCollator::QCollator(const QLocale &locale, QCollator::Collation collation)
146
: d(new QCollatorPrivate)
149
if ((int)collation >= 0 && (int)collation < collationStringsCount)
150
d->collation = collation;
156
Creates a copy of \a other.
158
QCollator::QCollator(const QCollator &other)
165
Destroys the collator.
167
QCollator::~QCollator()
174
Assigns \a other to this collator.
176
QCollator &QCollator::operator=(const QCollator &other)
178
if (this != &other) {
191
void QCollator::init()
193
Q_ASSERT((int)d->collation < collationStringsCount);
195
const char *collationString = collationStrings[(int)d->collation];
196
UErrorCode status = U_ZERO_ERROR;
197
QByteArray name = (d->locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')) + QLatin1String("@collation=") + QLatin1String(collationString)).toLatin1();
198
d->collator = ucol_open(name.constData(), &status);
199
if (U_FAILURE(status))
200
qWarning("Could not create collator: %d", status);
202
// enable normalization by default
203
ucol_setAttribute(d->collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
210
void QCollator::detach()
212
if (d->ref.load() != 1) {
213
QCollatorPrivate *x = new QCollatorPrivate;
215
x->locale = d->locale;
216
x->collation = d->collation;
226
Sets the locale of the collator to \a locale.
228
void QCollator::setLocale(const QLocale &locale)
230
if (d->ref.load() != 1)
239
Returns the locale of the collator.
241
QLocale QCollator::locale() const
247
\enum QCollator::Collation
249
This enum can be used to specify an alternate collation algorithm to be used instead
250
of the default algorithm for the locale.
254
\value Default Use the default algorithm for the locale
269
Sets the collation algorithm to be used.
271
\sa QCollator::Collation
273
void QCollator::setCollation(QCollator::Collation collation)
275
if ((int)collation < 0 || (int)collation >= collationStringsCount)
278
if (d->ref.load() != 1)
281
d->collation = collation;
286
Returns the currently used collation algorithm.
288
\sa QCollator::Collation
290
QCollator::Collation QCollator::collation() const
296
Returns a unique identifer for this collation object.
298
This method is helpful to save and restore defined collation
303
QString QCollator::identifier() const
305
QString id = d->locale.bcp47Name();
306
if (d->collation != QCollator::Default) {
307
id += QLatin1String("@collation=");
308
id += QLatin1String(collationStrings[d->collation]);
310
// this ensures the ID is compatible with ICU
311
id.replace('-', '_');
316
Creates a QCollator from a unique identifier and returns it.
320
QCollator QCollator::fromIdentifier(const QString &identifier)
322
QString localeString = identifier;
323
QString collationString;
324
int at = identifier.indexOf(QLatin1Char('@'));
326
localeString = identifier.left(at);
327
collationString = identifier.mid(at + strlen("@collation="));
330
QLocale locale(localeString);
331
Collation collation = Default;
332
if (!collationString.isEmpty()) {
333
for (int i = 0; i < collationStringsCount; ++i) {
334
if (QLatin1String(collationStrings[i]) == collationString) {
335
collation = Collation(i);
340
return QCollator(locale, collation);
344
\enum QCollator::CasePreference
346
This enum can be used to tailor the case preference during collation.
348
\value CasePreferenceOff No case preference, use what is the standard for the locale
349
\value CasePreferenceUpper Sort upper case characters before lower case
350
\value CasePreferenceLower Sort lower case characters before upper case
354
Sets the case preference of the collator.
356
\sa QCollator::CasePreference
358
void QCollator::setCasePreference(CasePreference c)
360
if (d->ref.load() != 1)
364
UColAttributeValue val = UCOL_OFF;
365
if (c == QCollator::CasePreferenceUpper)
366
val = UCOL_UPPER_FIRST;
367
else if (c == QCollator::CasePreferenceLower)
368
val = UCOL_LOWER_FIRST;
370
UErrorCode status = U_ZERO_ERROR;
371
ucol_setAttribute(d->collator, UCOL_CASE_FIRST, val, &status);
372
if (U_FAILURE(status))
373
qWarning("ucol_setAttribute: Case First failed: %d", status);
380
Returns case preference of the collator.
382
\sa QCollator::CasePreference
384
QCollator::CasePreference QCollator::casePreference() const
387
UErrorCode status = U_ZERO_ERROR;
388
switch (ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status)) {
389
case UCOL_UPPER_FIRST:
390
return QCollator::CasePreferenceUpper;
391
case UCOL_LOWER_FIRST:
392
return QCollator::CasePreferenceLower;
398
return QCollator::CasePreferenceOff;
402
Enables numeric sorting mode when \a on is set to true.
404
This will enable proper sorting of numeric digits, so that e.g. 100 sorts after 99.
406
By default this mode is off.
408
void QCollator::setNumericMode(bool on)
410
if (d->ref.load() != 1)
414
UErrorCode status = U_ZERO_ERROR;
415
ucol_setAttribute(d->collator, UCOL_NUMERIC_COLLATION, on ? UCOL_ON : UCOL_OFF, &status);
416
if (U_FAILURE(status))
417
qWarning("ucol_setAttribute: numeric collation failed: %d", status);
424
Returns true if numeric sorting is enabled, false otherwise.
428
bool QCollator::numericMode() const
432
if (ucol_getAttribute(d->collator, UCOL_NUMERIC_COLLATION, &status) == UCOL_ON)
439
If set to true, punctuation characters and symbols are ignored when determining sort order.
441
The default is locale dependent.
443
void QCollator::setIgnorePunctuation(bool on)
445
if (d->ref.load() != 1)
450
ucol_setAttribute(d->collator, UCOL_ALTERNATE_HANDLING, on ? UCOL_SHIFTED : UCOL_NON_IGNORABLE, &status);
451
if (U_FAILURE(status))
452
qWarning("ucol_setAttribute: Alternate handling failed: %d", status);
459
Returns true if punctuation characters and symbols are ignored when determining sort order.
461
\sa setIgnorePunctuation
463
bool QCollator::ignorePunctuation() const
467
if (ucol_getAttribute(d->collator, UCOL_ALTERNATE_HANDLING, &status) == UCOL_SHIFTED)
474
Compares \a s1 with \a s2. Returns -1, 0 or 1 depending on whether \a s1 is
475
smaller, equal or larger than \a s2.
477
int QCollator::compare(const QString &s1, const QString &s2) const
479
return compare(s1.constData(), s1.size(), s2.constData(), s2.size());
485
Compares \a s1 with \a s2. Returns -1, 0 or 1 depending on whether \a s1 is
486
smaller, equal or larger than \a s2.
488
int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
490
return compare(s1.constData(), s1.size(), s2.constData(), s2.size());
496
Compares \a s1 with \a s2. \a len1 and \a len2 specify the length of the
497
QChar arrays pointer to by \a s1 and \a s2.
499
Returns -1, 0 or 1 depending on whether \a s1 is smaller, equal or larger than \a s2.
501
int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
504
const UCollationResult result =
505
ucol_strcoll(d->collator, (const UChar *)s1, len1, (const UChar *)s2, len2);
508
return QString::compare_helper((const QChar *)s1, len1, (const QChar *)s2, len2, Qt::CaseInsensitive);
513
Returns a sortKey for \a string. The sortkey can be used as a placeholder
514
for the string that can be then sorted using regular strcmp based sorting.
516
Creating the sort key is usually somewhat slower, then using the compare()
517
methods directly. But if the string is compared repeatedly (e.g. when sorting
518
a whole list of strings), it's usually faster to create the sort keys for each
519
string and then sort using the keys.
521
QByteArray QCollator::sortKey(const QString &string) const
524
QByteArray result(16 + string.size() + (string.size() >> 2), Qt::Uninitialized);
525
int size = ucol_getSortKey(d->collator, (const UChar *)string.constData(),
526
string.size(), (uint8_t *)result.data(), result.size());
527
if (size > result.size()) {
529
size = ucol_getSortKey(d->collator, (const UChar *)string.constData(),
530
string.size(), (uint8_t *)result.data(), result.size());
532
result.truncate(size);
535
return string.toLower().toUtf8();
539
static QStringList englishIndexCharacters()
541
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");
542
return chars.split(QLatin1Char(' '), QString::SkipEmptyParts);
546
Returns a string list of primary index characters. This is useful when presenting the
547
sorted list in a user interface with section headers.
549
QStringList QCollator::indexCharacters() const
551
if (!d->indexCharacters.isEmpty())
552
return d->indexCharacters;
555
QByteArray id = identifier().toLatin1();
557
UErrorCode status = U_ZERO_ERROR;
558
UResourceBundle *res = ures_open(NULL, id, &status);
560
if (U_FAILURE(status)) {
561
d->indexCharacters = englishIndexCharacters();
565
status = U_ZERO_ERROR;
566
const UChar *val = ures_getStringByKey(res, "ExemplarCharactersIndex", &len, &status);
567
if (U_FAILURE(status)) {
568
d->indexCharacters = englishIndexCharacters();
570
QString chars(reinterpret_cast<const QChar *>(val), len);
575
d->indexCharacters = chars.split(QLatin1Char(' '), QString::SkipEmptyParts);
581
d->indexCharacters = englishIndexCharacters();
584
return d->indexCharacters;