Remove incorrect assertions
[qBittorrent.git] / src / gui / transferlistsortmodel.cpp
blob131d729a2723c31b68d677437cc3eb822cc1374a
1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2013 Nick Tiskov <daymansmail@gmail.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * In addition, as a special exception, the copyright holders give permission to
20 * link this program with the OpenSSL project's "OpenSSL" library (or with
21 * modified versions of it that use the same license as the "OpenSSL" library),
22 * and distribute the linked executables. You must obey the GNU General Public
23 * License in all respects for all of the code used other than "OpenSSL". If you
24 * modify file(s), you may extend this exception to your version of the file(s),
25 * but you are not obligated to do so. If you do not wish to do so, delete this
26 * exception statement from your version.
29 #include "transferlistsortmodel.h"
31 #include <type_traits>
33 #include <QDateTime>
35 #include "base/bittorrent/infohash.h"
36 #include "base/bittorrent/torrent.h"
37 #include "transferlistmodel.h"
39 namespace
41 template <typename T>
42 int threeWayCompare(const T &left, const T &right)
44 if (left == right)
45 return 0;
46 return (left < right) ? -1 : 1;
49 int customCompare(const QDateTime &left, const QDateTime &right)
51 const bool isLeftValid = left.isValid();
52 const bool isRightValid = right.isValid();
54 if (isLeftValid == isRightValid)
55 return threeWayCompare(left, right);
56 return isLeftValid ? -1 : 1;
59 int customCompare(const TagSet &left, const TagSet &right, const Utils::Compare::NaturalCompare<Qt::CaseInsensitive> &compare)
61 for (auto leftIter = left.cbegin(), rightIter = right.cbegin();
62 (leftIter != left.cend()) && (rightIter != right.cend());
63 ++leftIter, ++rightIter)
65 const int result = compare(*leftIter, *rightIter);
66 if (result != 0)
67 return result;
69 return threeWayCompare(left.size(), right.size());
72 template <typename T>
73 int customCompare(const T left, const T right)
75 static_assert(std::is_arithmetic_v<T>);
77 const bool isLeftValid = (left >= 0);
78 const bool isRightValid = (right >= 0);
80 if (isLeftValid && isRightValid)
81 return threeWayCompare(left, right);
82 if (!isLeftValid && !isRightValid)
83 return 0;
84 return isLeftValid ? -1 : 1;
87 int adjustSubSortColumn(const int column)
89 return ((column >= 0) && (column < TransferListModel::NB_COLUMNS))
90 ? column : TransferListModel::TR_NAME;
94 TransferListSortModel::TransferListSortModel(QObject *parent)
95 : QSortFilterProxyModel {parent}
96 , m_subSortColumn {u"TransferList/SubSortColumn"_s, TransferListModel::TR_NAME, adjustSubSortColumn}
97 , m_subSortOrder {u"TransferList/SubSortOrder"_s, 0}
99 setSortRole(TransferListModel::UnderlyingDataRole);
102 void TransferListSortModel::sort(const int column, const Qt::SortOrder order)
104 if ((m_lastSortColumn != column) && (m_lastSortColumn != -1))
106 m_subSortColumn = m_lastSortColumn;
107 m_subSortOrder = m_lastSortOrder;
109 m_lastSortColumn = column;
110 m_lastSortOrder = ((order == Qt::AscendingOrder) ? 0 : 1);
112 QSortFilterProxyModel::sort(column, order);
115 void TransferListSortModel::setStatusFilter(TorrentFilter::Type filter)
117 if (m_filter.setType(filter))
118 invalidateFilter();
121 void TransferListSortModel::setCategoryFilter(const QString &category)
123 if (m_filter.setCategory(category))
124 invalidateFilter();
127 void TransferListSortModel::disableCategoryFilter()
129 if (m_filter.setCategory(TorrentFilter::AnyCategory))
130 invalidateFilter();
133 void TransferListSortModel::setTagFilter(const QString &tag)
135 if (m_filter.setTag(tag))
136 invalidateFilter();
139 void TransferListSortModel::disableTagFilter()
141 if (m_filter.setTag(TorrentFilter::AnyTag))
142 invalidateFilter();
145 void TransferListSortModel::setTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs)
147 if (m_filter.setTorrentIDSet(torrentIDs))
148 invalidateFilter();
151 void TransferListSortModel::disableTrackerFilter()
153 if (m_filter.setTorrentIDSet(TorrentFilter::AnyID))
154 invalidateFilter();
157 int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &right) const
159 const int compareColumn = left.column();
160 const QVariant leftValue = left.data(TransferListModel::UnderlyingDataRole);
161 const QVariant rightValue = right.data(TransferListModel::UnderlyingDataRole);
163 switch (compareColumn)
165 case TransferListModel::TR_CATEGORY:
166 case TransferListModel::TR_DOWNLOAD_PATH:
167 case TransferListModel::TR_NAME:
168 case TransferListModel::TR_SAVE_PATH:
169 case TransferListModel::TR_TRACKER:
170 return m_naturalCompare(leftValue.toString(), rightValue.toString());
172 case TransferListModel::TR_INFOHASH_V1:
173 return threeWayCompare(leftValue.value<SHA1Hash>(), rightValue.value<SHA1Hash>());
175 case TransferListModel::TR_INFOHASH_V2:
176 return threeWayCompare(leftValue.value<SHA256Hash>(), rightValue.value<SHA256Hash>());
178 case TransferListModel::TR_TAGS:
179 return customCompare(leftValue.value<TagSet>(), rightValue.value<TagSet>(), m_naturalCompare);
181 case TransferListModel::TR_AMOUNT_DOWNLOADED:
182 case TransferListModel::TR_AMOUNT_DOWNLOADED_SESSION:
183 case TransferListModel::TR_AMOUNT_LEFT:
184 case TransferListModel::TR_AMOUNT_UPLOADED:
185 case TransferListModel::TR_AMOUNT_UPLOADED_SESSION:
186 case TransferListModel::TR_COMPLETED:
187 case TransferListModel::TR_ETA:
188 case TransferListModel::TR_LAST_ACTIVITY:
189 case TransferListModel::TR_SIZE:
190 case TransferListModel::TR_TIME_ELAPSED:
191 case TransferListModel::TR_TOTAL_SIZE:
192 return customCompare(leftValue.toLongLong(), rightValue.toLongLong());
194 case TransferListModel::TR_AVAILABILITY:
195 case TransferListModel::TR_PROGRESS:
196 case TransferListModel::TR_RATIO:
197 case TransferListModel::TR_RATIO_LIMIT:
198 return customCompare(leftValue.toReal(), rightValue.toReal());
200 case TransferListModel::TR_STATUS:
201 return threeWayCompare(leftValue.toInt(), rightValue.toInt());
203 case TransferListModel::TR_ADD_DATE:
204 case TransferListModel::TR_SEED_DATE:
205 case TransferListModel::TR_SEEN_COMPLETE_DATE:
206 return customCompare(leftValue.toDateTime(), rightValue.toDateTime());
208 case TransferListModel::TR_DLLIMIT:
209 case TransferListModel::TR_DLSPEED:
210 case TransferListModel::TR_QUEUE_POSITION:
211 case TransferListModel::TR_UPLIMIT:
212 case TransferListModel::TR_UPSPEED:
213 return customCompare(leftValue.toInt(), rightValue.toInt());
215 case TransferListModel::TR_PEERS:
216 case TransferListModel::TR_SEEDS:
218 // Active peers/seeds take precedence over total peers/seeds
219 const auto activeL = leftValue.toInt();
220 const auto activeR = rightValue.toInt();
221 if (activeL != activeR)
222 return threeWayCompare(activeL, activeR);
224 const auto totalL = left.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
225 const auto totalR = right.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
226 return threeWayCompare(totalL, totalR);
229 default:
230 Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case");
231 break;
234 return 0;
237 bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
239 Q_ASSERT(left.column() == right.column());
241 const int result = compare(left, right);
242 if (result == 0)
244 const int subResult = compare(left.sibling(left.row(), m_subSortColumn), right.sibling(right.row(), m_subSortColumn));
245 // Qt inverses lessThan() result when ordered descending.
246 // For sub-sorting we have to do it manually.
247 // When both are ordered descending subResult must be double-inversed, which is the same as no inversion.
248 const bool inverseSubResult = (m_lastSortOrder != m_subSortOrder); // exactly one is descending
249 return (inverseSubResult ? (subResult > 0) : (subResult < 0));
252 return result < 0;
255 bool TransferListSortModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
257 return matchFilter(sourceRow, sourceParent)
258 && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
261 bool TransferListSortModel::matchFilter(const int sourceRow, const QModelIndex &sourceParent) const
263 const auto *model = qobject_cast<TransferListModel *>(sourceModel());
264 if (!model) return false;
266 const BitTorrent::Torrent *torrent = model->torrentHandle(model->index(sourceRow, 0, sourceParent));
267 if (!torrent) return false;
269 return m_filter.match(torrent);