diff --git a/src/app/application.cpp b/src/app/application.cpp index 4cd910191..801010c71 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -78,9 +78,9 @@ #include "base/scanfoldersmodel.h" #include "base/search/searchpluginmanager.h" #include "base/settingsstorage.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" #include "base/utils/misc.h" -#include "base/utils/string.h" #include "base/version.h" #include "applicationinstancemanager.h" #include "filelogger.h" @@ -352,7 +352,7 @@ void Application::runExternalProgram(const BitTorrent::Torrent *torrent) const case u'G': { QStringList tags = torrent->tags().values(); - std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan); + std::sort(tags.begin(), tags.end(), Utils::Compare::NaturalLessThan()); program.replace(i, 2, tags.join(',')); } break; diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt index 681ab4afa..2067d5316 100644 --- a/src/base/CMakeLists.txt +++ b/src/base/CMakeLists.txt @@ -79,6 +79,7 @@ add_library(qbt_base STATIC types.h unicodestrings.h utils/bytearray.h + utils/compare.h utils/foreignapps.h utils/fs.h utils/gzip.h @@ -154,6 +155,7 @@ add_library(qbt_base STATIC torrentfileguard.cpp torrentfilter.cpp utils/bytearray.cpp + utils/compare.cpp utils/foreignapps.cpp utils/fs.cpp utils/gzip.cpp diff --git a/src/base/base.pri b/src/base/base.pri index d80f97393..4b0738c22 100644 --- a/src/base/base.pri +++ b/src/base/base.pri @@ -79,6 +79,7 @@ HEADERS += \ $$PWD/types.h \ $$PWD/unicodestrings.h \ $$PWD/utils/bytearray.h \ + $$PWD/utils/compare.h \ $$PWD/utils/foreignapps.h \ $$PWD/utils/fs.h \ $$PWD/utils/gzip.h \ @@ -154,6 +155,7 @@ SOURCES += \ $$PWD/torrentfileguard.cpp \ $$PWD/torrentfilter.cpp \ $$PWD/utils/bytearray.cpp \ + $$PWD/utils/compare.cpp \ $$PWD/utils/foreignapps.cpp \ $$PWD/utils/fs.cpp \ $$PWD/utils/gzip.cpp \ diff --git a/src/base/bittorrent/torrentcreatorthread.cpp b/src/base/bittorrent/torrentcreatorthread.cpp index bdd329634..892dd05e9 100644 --- a/src/base/bittorrent/torrentcreatorthread.cpp +++ b/src/base/bittorrent/torrentcreatorthread.cpp @@ -42,9 +42,9 @@ #include "base/exceptions.h" #include "base/global.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" #include "base/utils/io.h" -#include "base/utils/string.h" #include "base/version.h" #include "ltunderlyingtype.h" @@ -105,6 +105,7 @@ void TorrentCreatorThread::run() try { const QString parentPath = Utils::Fs::branchPath(m_params.inputPath) + '/'; + const Utils::Compare::NaturalLessThan naturalLessThan {}; // Adding files to the torrent lt::file_storage fs; @@ -123,7 +124,7 @@ void TorrentCreatorThread::run() dirIter.next(); dirs += dirIter.filePath(); } - std::sort(dirs.begin(), dirs.end(), Utils::String::naturalLessThan); + std::sort(dirs.begin(), dirs.end(), naturalLessThan); QStringList fileNames; QHash fileSizeMap; @@ -142,7 +143,7 @@ void TorrentCreatorThread::run() fileSizeMap[relFilePath] = fileIter.fileInfo().size(); } - std::sort(tmpNames.begin(), tmpNames.end(), Utils::String::naturalLessThan); + std::sort(tmpNames.begin(), tmpNames.end(), naturalLessThan); fileNames += tmpNames; } diff --git a/src/base/utils/compare.cpp b/src/base/utils/compare.cpp new file mode 100644 index 000000000..343ff01f5 --- /dev/null +++ b/src/base/utils/compare.cpp @@ -0,0 +1,96 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2021 Mike Tzou (Chocobo1) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "compare.h" + +#include +#include + +#ifndef QBT_USE_QCOLLATOR +int Utils::Compare::naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity) +{ + // Return value <0: `left` is smaller than `right` + // Return value >0: `left` is greater than `right` + // Return value =0: both strings are equal + + int posL = 0; + int posR = 0; + while (true) + { + if ((posL == left.size()) || (posR == right.size())) + return (left.size() - right.size()); // when a shorter string is another string's prefix, shorter string place before longer string + + const QChar leftChar = (caseSensitivity == Qt::CaseSensitive) ? left[posL] : left[posL].toLower(); + const QChar rightChar = (caseSensitivity == Qt::CaseSensitive) ? right[posR] : right[posR].toLower(); + // Compare only non-digits. + // Numbers should be compared as a whole + // otherwise the string->int conversion can yield a wrong value + if ((leftChar == rightChar) && !leftChar.isDigit()) + { + // compare next character + ++posL; + ++posR; + } + else if (leftChar.isDigit() && rightChar.isDigit()) + { + // Both are digits, compare the numbers + + const auto numberView = [](const QString &str, int &pos) -> QStringRef + { + const int start = pos; + while ((pos < str.size()) && str[pos].isDigit()) + ++pos; + return str.midRef(start, (pos - start)); + }; + + const QStringRef numViewL = numberView(left, posL); + const QStringRef numViewR = numberView(right, posR); + + if (numViewL.length() != numViewR.length()) + return (numViewL.length() - numViewR.length()); + + // both string/view has the same length + for (int i = 0; i < numViewL.length(); ++i) + { + const QChar numL = numViewL[i]; + const QChar numR = numViewR[i]; + + if (numL != numR) + return (numL.unicode() - numR.unicode()); + } + + // String + digits do match and we haven't hit the end of both strings + // then continue to consume the remainings + } + else + { + return (leftChar.unicode() - rightChar.unicode()); + } + } +} +#endif diff --git a/src/base/utils/compare.h b/src/base/utils/compare.h new file mode 100644 index 000000000..7673b0f7f --- /dev/null +++ b/src/base/utils/compare.h @@ -0,0 +1,88 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2021 Mike Tzou (Chocobo1) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +#include +#include + +#ifndef Q_OS_WIN +#define QBT_USE_QCOLLATOR +#include +#endif + +class QString; + +namespace Utils::Compare +{ +#ifdef QBT_USE_QCOLLATOR + template + class NaturalCompare + { + public: + NaturalCompare() + { + m_collator.setNumericMode(true); + m_collator.setCaseSensitivity(caseSensitivity); + } + + int operator()(const QString &left, const QString &right) const + { + return m_collator.compare(left, right); + } + + private: + QCollator m_collator; + }; +#else + int naturalCompare(const QString &left, const QString &right, Qt::CaseSensitivity caseSensitivity); + + template + class NaturalCompare + { + public: + int operator()(const QString &left, const QString &right) const + { + return naturalCompare(left, right, caseSensitivity); + } + }; +#endif + + template + class NaturalLessThan + { + public: + bool operator()(const QString &left, const QString &right) const + { + return (m_comparator(left, right) < 0); + } + + private: + NaturalCompare m_comparator; + }; +} diff --git a/src/base/utils/string.cpp b/src/base/utils/string.cpp index 7256352c4..46b2c4450 100644 --- a/src/base/utils/string.cpp +++ b/src/base/utils/string.cpp @@ -31,9 +31,7 @@ #include -#include #include -#include #include #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) @@ -42,137 +40,6 @@ #include #endif -#if defined(Q_OS_MACOS) || defined(__MINGW32__) -#define QBT_USES_QTHREADSTORAGE -#include -#endif - -namespace -{ - class NaturalCompare - { - public: - explicit NaturalCompare(const Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive) - : m_caseSensitivity(caseSensitivity) - { -#ifdef Q_OS_WIN - // Without ICU library, QCollator uses the native API on Windows 7+. But that API - // sorts older versions of μTorrent differently than the newer ones because the - // 'μ' character is encoded differently and the native API can't cope with that. - // So default to using our custom natural sorting algorithm instead. - // See #5238 and #5240 - // Without ICU library, QCollator doesn't support `setNumericMode(true)` on an OS older than Win7 -#else - m_collator.setNumericMode(true); - m_collator.setCaseSensitivity(caseSensitivity); -#endif - } - - int operator()(const QString &left, const QString &right) const - { -#ifdef Q_OS_WIN - return compare(left, right); -#else - return m_collator.compare(left, right); -#endif - } - - private: - int compare(const QString &left, const QString &right) const - { - // Return value <0: `left` is smaller than `right` - // Return value >0: `left` is greater than `right` - // Return value =0: both strings are equal - - int posL = 0; - int posR = 0; - while (true) - { - if ((posL == left.size()) || (posR == right.size())) - return (left.size() - right.size()); // when a shorter string is another string's prefix, shorter string place before longer string - - const QChar leftChar = (m_caseSensitivity == Qt::CaseSensitive) ? left[posL] : left[posL].toLower(); - const QChar rightChar = (m_caseSensitivity == Qt::CaseSensitive) ? right[posR] : right[posR].toLower(); - // Compare only non-digits. - // Numbers should be compared as a whole - // otherwise the string->int conversion can yield a wrong value - if ((leftChar == rightChar) && !leftChar.isDigit()) - { - // compare next character - ++posL; - ++posR; - } - else if (leftChar.isDigit() && rightChar.isDigit()) - { - // Both are digits, compare the numbers - - const auto numberView = [](const QString &str, int &pos) -> QStringRef - { - const int start = pos; - while ((pos < str.size()) && str[pos].isDigit()) - ++pos; - return str.midRef(start, (pos - start)); - }; - - const QStringRef numViewL = numberView(left, posL); - const QStringRef numViewR = numberView(right, posR); - - if (numViewL.length() != numViewR.length()) - return (numViewL.length() - numViewR.length()); - - // both string/view has the same length - for (int i = 0; i < numViewL.length(); ++i) - { - const QChar numL = numViewL[i]; - const QChar numR = numViewR[i]; - - if (numL != numR) - return (numL.unicode() - numR.unicode()); - } - - // String + digits do match and we haven't hit the end of both strings - // then continue to consume the remainings - } - else - { - return (leftChar.unicode() - rightChar.unicode()); - } - } - } - - QCollator m_collator; - const Qt::CaseSensitivity m_caseSensitivity; - }; -} - -int Utils::String::naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity) -{ - // provide a single `NaturalCompare` instance for easy use - // https://doc.qt.io/qt-5/threads-reentrancy.html - if (caseSensitivity == Qt::CaseSensitive) - { -#ifdef QBT_USES_QTHREADSTORAGE - static QThreadStorage nCmp; - if (!nCmp.hasLocalData()) - nCmp.setLocalData(NaturalCompare(Qt::CaseSensitive)); - return (nCmp.localData())(left, right); -#else - thread_local NaturalCompare nCmp(Qt::CaseSensitive); - return nCmp(left, right); -#endif - } - -#ifdef QBT_USES_QTHREADSTORAGE - static QThreadStorage nCmp; - if (!nCmp.hasLocalData()) - nCmp.setLocalData(NaturalCompare(Qt::CaseInsensitive)); - return (nCmp.localData())(left, right); -#else - thread_local NaturalCompare nCmp(Qt::CaseInsensitive); - return nCmp(left, right); -#endif -} - // to send numbers instead of strings with suffixes QString Utils::String::fromDouble(const double n, const int precision) { diff --git a/src/base/utils/string.h b/src/base/utils/string.h index 7531a312b..e7ff9919b 100644 --- a/src/base/utils/string.h +++ b/src/base/utils/string.h @@ -41,15 +41,6 @@ class QStringRef; namespace Utils::String { - QString fromDouble(double n, int precision); - - int naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity); - template - bool naturalLessThan(const QString &left, const QString &right) - { - return (naturalCompare(left, right, caseSensitivity) < 0); - } - QString wildcardToRegexPattern(const QString &pattern); template @@ -72,6 +63,8 @@ namespace Utils::String QString join(const QVector &strings, const QString &separator); + QString fromDouble(double n, int precision); + template , int> = 0> QString fromEnum(const T &value) { diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp index e6d66993b..b39043b25 100644 --- a/src/gui/addnewtorrentdialog.cpp +++ b/src/gui/addnewtorrentdialog.cpp @@ -48,9 +48,9 @@ #include "base/net/downloadmanager.h" #include "base/settingsstorage.h" #include "base/torrentfileguard.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" #include "base/utils/misc.h" -#include "base/utils/string.h" #include "autoexpandabledialog.h" #include "properties/proplistdelegate.h" #include "raisedmessagebox.h" @@ -129,7 +129,7 @@ AddNewTorrentDialog::AddNewTorrentDialog(const BitTorrent::AddTorrentParams &inP // Load categories QStringList categories = session->categories().keys(); - std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan); + std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan()); auto defaultCategory = settings()->loadValue(KEY_DEFAULTCATEGORY); if (!m_torrentParams.category.isEmpty()) diff --git a/src/gui/categoryfilterproxymodel.cpp b/src/gui/categoryfilterproxymodel.cpp index d9ba958ca..f3f1b67c4 100644 --- a/src/gui/categoryfilterproxymodel.cpp +++ b/src/gui/categoryfilterproxymodel.cpp @@ -28,7 +28,6 @@ #include "categoryfilterproxymodel.h" -#include "base/utils/string.h" #include "categoryfiltermodel.h" CategoryFilterProxyModel::CategoryFilterProxyModel(QObject *parent) @@ -51,9 +50,5 @@ bool CategoryFilterProxyModel::lessThan(const QModelIndex &left, const QModelInd // "All" and "Uncategorized" must be left in place if (CategoryFilterModel::isSpecialItem(left) || CategoryFilterModel::isSpecialItem(right)) return (left < right); - - int result = Utils::String::naturalCompare(left.data().toString(), right.data().toString() - , Qt::CaseInsensitive); - - return (result < 0); + return m_naturalLessThan(left.data().toString(), right.data().toString()); } diff --git a/src/gui/categoryfilterproxymodel.h b/src/gui/categoryfilterproxymodel.h index 592dc2f81..a65d3fead 100644 --- a/src/gui/categoryfilterproxymodel.h +++ b/src/gui/categoryfilterproxymodel.h @@ -30,6 +30,8 @@ #include +#include "base/utils/compare.h" + class QString; class CategoryFilterProxyModel final : public QSortFilterProxyModel @@ -47,4 +49,6 @@ protected: private: // we added another overload of index(), hence this using directive: using QSortFilterProxyModel::index; + + Utils::Compare::NaturalLessThan m_naturalLessThan; }; diff --git a/src/gui/properties/peerlistsortmodel.cpp b/src/gui/properties/peerlistsortmodel.cpp index 158acb5b6..27776c180 100644 --- a/src/gui/properties/peerlistsortmodel.cpp +++ b/src/gui/properties/peerlistsortmodel.cpp @@ -28,7 +28,6 @@ #include "peerlistsortmodel.h" -#include "base/utils/string.h" #include "peerlistwidget.h" PeerListSortModel::PeerListSortModel(QObject *parent) @@ -43,11 +42,10 @@ bool PeerListSortModel::lessThan(const QModelIndex &left, const QModelIndex &rig { case PeerListWidget::IP: case PeerListWidget::CLIENT: - { + { const QString strL = left.data(UnderlyingDataRole).toString(); const QString strR = right.data(UnderlyingDataRole).toString(); - const int result = Utils::String::naturalCompare(strL, strR, Qt::CaseInsensitive); - return (result < 0); + return m_naturalLessThan(strL, strR); } break; default: diff --git a/src/gui/properties/peerlistsortmodel.h b/src/gui/properties/peerlistsortmodel.h index aa66497bc..c00d87984 100644 --- a/src/gui/properties/peerlistsortmodel.h +++ b/src/gui/properties/peerlistsortmodel.h @@ -30,6 +30,8 @@ #include +#include "base/utils/compare.h" + class PeerListSortModel final : public QSortFilterProxyModel { Q_OBJECT @@ -45,4 +47,6 @@ public: private: bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + + Utils::Compare::NaturalLessThan m_naturalLessThan; }; diff --git a/src/gui/rss/automatedrssdownloader.cpp b/src/gui/rss/automatedrssdownloader.cpp index fb0313799..98e3f63cd 100644 --- a/src/gui/rss/automatedrssdownloader.cpp +++ b/src/gui/rss/automatedrssdownloader.cpp @@ -47,6 +47,7 @@ #include "base/rss/rss_feed.h" #include "base/rss/rss_folder.h" #include "base/rss/rss_session.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" #include "base/utils/string.h" #include "gui/autoexpandabledialog.h" @@ -330,7 +331,7 @@ void AutomatedRssDownloader::initCategoryCombobox() { // Load torrent categories QStringList categories = BitTorrent::Session::instance()->categories().keys(); - std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan); + std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan()); m_ui->comboCategory->addItem(""); m_ui->comboCategory->addItems(categories); } diff --git a/src/gui/search/searchsortmodel.cpp b/src/gui/search/searchsortmodel.cpp index 7ca7bb527..1af053634 100644 --- a/src/gui/search/searchsortmodel.cpp +++ b/src/gui/search/searchsortmodel.cpp @@ -29,7 +29,6 @@ #include "searchsortmodel.h" #include "base/global.h" -#include "base/utils/string.h" SearchSortModel::SearchSortModel(QObject *parent) : base(parent) @@ -118,11 +117,10 @@ bool SearchSortModel::lessThan(const QModelIndex &left, const QModelIndex &right { case NAME: case ENGINE_URL: - { + { const QString strL = left.data().toString(); const QString strR = right.data().toString(); - const int result = Utils::String::naturalCompare(strL, strR, Qt::CaseInsensitive); - return (result < 0); + return m_naturalLessThan(strL, strR); } break; default: diff --git a/src/gui/search/searchsortmodel.h b/src/gui/search/searchsortmodel.h index fda94cc6d..c5cf785bd 100644 --- a/src/gui/search/searchsortmodel.h +++ b/src/gui/search/searchsortmodel.h @@ -31,6 +31,8 @@ #include #include +#include "base/utils/compare.h" + class SearchSortModel final : public QSortFilterProxyModel { using base = QSortFilterProxyModel; @@ -94,4 +96,6 @@ private: int m_minSeeds, m_maxSeeds; int m_minLeeches, m_maxLeeches; qint64 m_minSize, m_maxSize; + + Utils::Compare::NaturalLessThan m_naturalLessThan; }; diff --git a/src/gui/tagfilterproxymodel.cpp b/src/gui/tagfilterproxymodel.cpp index c73d2e7ec..732888c48 100644 --- a/src/gui/tagfilterproxymodel.cpp +++ b/src/gui/tagfilterproxymodel.cpp @@ -28,7 +28,6 @@ #include "tagfilterproxymodel.h" -#include "base/utils/string.h" #include "tagfiltermodel.h" TagFilterProxyModel::TagFilterProxyModel(QObject *parent) @@ -51,8 +50,5 @@ bool TagFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &r // "All" and "Untagged" must be left in place if (TagFilterModel::isSpecialItem(left) || TagFilterModel::isSpecialItem(right)) return (left < right); - - int result = Utils::String::naturalCompare(left.data().toString(), right.data().toString() - , Qt::CaseInsensitive); - return (result < 0); + return m_naturalLessThan(left.data().toString(), right.data().toString()); } diff --git a/src/gui/tagfilterproxymodel.h b/src/gui/tagfilterproxymodel.h index e4664e98c..40390812f 100644 --- a/src/gui/tagfilterproxymodel.h +++ b/src/gui/tagfilterproxymodel.h @@ -30,6 +30,8 @@ #include +#include "base/utils/compare.h" + class QString; class TagFilterProxyModel final : public QSortFilterProxyModel @@ -47,4 +49,6 @@ protected: private: // we added another overload of index(), hence this using directive: using QSortFilterProxyModel::index; + + Utils::Compare::NaturalLessThan m_naturalLessThan; }; diff --git a/src/gui/torrentcontentfiltermodel.cpp b/src/gui/torrentcontentfiltermodel.cpp index 465a21164..59e2e4771 100644 --- a/src/gui/torrentcontentfiltermodel.cpp +++ b/src/gui/torrentcontentfiltermodel.cpp @@ -28,7 +28,6 @@ #include "torrentcontentfiltermodel.h" -#include "base/utils/string.h" #include "torrentcontentmodel.h" TorrentContentFilterModel::TorrentContentFilterModel(QObject *parent) @@ -94,7 +93,7 @@ bool TorrentContentFilterModel::lessThan(const QModelIndex &left, const QModelIn { const QString strL = left.data().toString(); const QString strR = right.data().toString(); - return Utils::String::naturalLessThan(strL, strR); + return m_naturalLessThan(strL, strR); } if ((leftType == TorrentContentModelItem::FolderType) && (sortOrder() == Qt::AscendingOrder)) { diff --git a/src/gui/torrentcontentfiltermodel.h b/src/gui/torrentcontentfiltermodel.h index 993502454..a23f31c16 100644 --- a/src/gui/torrentcontentfiltermodel.h +++ b/src/gui/torrentcontentfiltermodel.h @@ -30,6 +30,7 @@ #include +#include "base/utils/compare.h" #include "torrentcontentmodelitem.h" class TorrentContentModel; @@ -61,4 +62,5 @@ private: bool hasFiltered(const QModelIndex &folder) const; TorrentContentModel *m_model; + Utils::Compare::NaturalLessThan m_naturalLessThan; }; diff --git a/src/gui/transferlistfilterswidget.cpp b/src/gui/transferlistfilterswidget.cpp index 678b50ddd..6de04b7e8 100644 --- a/src/gui/transferlistfilterswidget.cpp +++ b/src/gui/transferlistfilterswidget.cpp @@ -47,8 +47,8 @@ #include "base/net/downloadmanager.h" #include "base/preferences.h" #include "base/torrentfilter.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" -#include "base/utils/string.h" #include "categoryfilterwidget.h" #include "tagfilterwidget.h" #include "transferlistwidget.h" @@ -366,10 +366,11 @@ void TrackerFiltersList::addItem(const QString &tracker, const BitTorrent::Torre } Q_ASSERT(count() >= 4); + const Utils::Compare::NaturalLessThan naturalLessThan {}; int insPos = count(); for (int i = 4; i < count(); ++i) { - if (Utils::String::naturalLessThan(host, item(i)->text())) + if (naturalLessThan(host, item(i)->text())) { insPos = i; break; diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 59b686161..fddf232e6 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -34,7 +34,6 @@ #include "base/bittorrent/infohash.h" #include "base/bittorrent/torrent.h" -#include "base/utils/string.h" #include "transferlistmodel.h" namespace @@ -143,7 +142,7 @@ int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &r case TransferListModel::TR_SAVE_PATH: case TransferListModel::TR_TAGS: case TransferListModel::TR_TRACKER: - return Utils::String::naturalCompare(leftValue.toString(), rightValue.toString(), Qt::CaseInsensitive); + return m_naturalCompare(leftValue.toString(), rightValue.toString()); case TransferListModel::TR_AMOUNT_DOWNLOADED: case TransferListModel::TR_AMOUNT_DOWNLOADED_SESSION: diff --git a/src/gui/transferlistsortmodel.h b/src/gui/transferlistsortmodel.h index 9c29a073f..b860098b2 100644 --- a/src/gui/transferlistsortmodel.h +++ b/src/gui/transferlistsortmodel.h @@ -32,6 +32,7 @@ #include "base/settingvalue.h" #include "base/torrentfilter.h" +#include "base/utils/compare.h" namespace BitTorrent { @@ -64,4 +65,6 @@ private: TorrentFilter m_filter; mutable CachedSettingValue m_subSortColumn; mutable int m_lastSortColumn = -1; + + Utils::Compare::NaturalCompare m_naturalCompare; }; diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 17d3719b1..151d059c7 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -52,6 +52,7 @@ #include "base/logger.h" #include "base/preferences.h" #include "base/torrentfilter.h" +#include "base/utils/compare.h" #include "base/utils/fs.h" #include "base/utils/misc.h" #include "base/utils/string.h" @@ -963,7 +964,7 @@ void TransferListWidget::displayListMenu(const QPoint &) // Category Menu QStringList categories = BitTorrent::Session::instance()->categories().keys(); - std::sort(categories.begin(), categories.end(), Utils::String::naturalLessThan); + std::sort(categories.begin(), categories.end(), Utils::Compare::NaturalLessThan()); QMenu *categoryMenu = listMenu->addMenu(UIThemeManager::instance()->getIcon("view-categories"), tr("Category")); @@ -988,7 +989,7 @@ void TransferListWidget::displayListMenu(const QPoint &) // Tag Menu QStringList tags(BitTorrent::Session::instance()->tags().values()); - std::sort(tags.begin(), tags.end(), Utils::String::naturalLessThan); + std::sort(tags.begin(), tags.end(), Utils::Compare::NaturalLessThan()); QMenu *tagsMenu = listMenu->addMenu(UIThemeManager::instance()->getIcon("view-categories"), tr("Tags"));