Sync translations from Transifex and run lupdate
[qBittorrent.git] / src / gui / transferlistsortmodel.cpp
bloba3826cabc6de57733a3a872a3d7fa33cbc5426ac
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 if (!isLeftValid && !isRightValid)
57 return 0;
58 return isLeftValid ? -1 : 1;
61 int customCompare(const TagSet &left, const TagSet &right, const Utils::Compare::NaturalCompare<Qt::CaseInsensitive> &compare)
63 for (auto leftIter = left.cbegin(), rightIter = right.cbegin();
64 (leftIter != left.cend()) && (rightIter != right.cend());
65 ++leftIter, ++rightIter)
67 const int result = compare(*leftIter, *rightIter);
68 if (result != 0)
69 return result;
71 return threeWayCompare(left.size(), right.size());
74 template <typename T>
75 int customCompare(const T left, const T right)
77 static_assert(std::is_arithmetic_v<T>);
79 const bool isLeftValid = (left >= 0);
80 const bool isRightValid = (right >= 0);
82 if (isLeftValid && isRightValid)
83 return threeWayCompare(left, right);
84 if (!isLeftValid && !isRightValid)
85 return 0;
86 return isLeftValid ? -1 : 1;
89 int adjustSubSortColumn(const int column)
91 return ((column >= 0) && (column < TransferListModel::NB_COLUMNS))
92 ? column : TransferListModel::TR_NAME;
96 TransferListSortModel::TransferListSortModel(QObject *parent)
97 : QSortFilterProxyModel {parent}
98 , m_subSortColumn {"TransferList/SubSortColumn", TransferListModel::TR_NAME, adjustSubSortColumn}
99 , m_subSortOrder {"TransferList/SubSortOrder", 0}
101 setSortRole(TransferListModel::UnderlyingDataRole);
104 void TransferListSortModel::sort(const int column, const Qt::SortOrder order)
106 if ((m_lastSortColumn != column) && (m_lastSortColumn != -1))
108 m_subSortColumn = m_lastSortColumn;
109 m_subSortOrder = m_lastSortOrder;
111 m_lastSortColumn = column;
112 m_lastSortOrder = ((order == Qt::AscendingOrder) ? 0 : 1);
114 QSortFilterProxyModel::sort(column, order);
117 void TransferListSortModel::setStatusFilter(TorrentFilter::Type filter)
119 if (m_filter.setType(filter))
120 invalidateFilter();
123 void TransferListSortModel::setCategoryFilter(const QString &category)
125 if (m_filter.setCategory(category))
126 invalidateFilter();
129 void TransferListSortModel::disableCategoryFilter()
131 if (m_filter.setCategory(TorrentFilter::AnyCategory))
132 invalidateFilter();
135 void TransferListSortModel::setTagFilter(const QString &tag)
137 if (m_filter.setTag(tag))
138 invalidateFilter();
141 void TransferListSortModel::disableTagFilter()
143 if (m_filter.setTag(TorrentFilter::AnyTag))
144 invalidateFilter();
147 void TransferListSortModel::setTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs)
149 if (m_filter.setTorrentIDSet(torrentIDs))
150 invalidateFilter();
153 void TransferListSortModel::disableTrackerFilter()
155 if (m_filter.setTorrentIDSet(TorrentFilter::AnyID))
156 invalidateFilter();
159 int TransferListSortModel::compare(const QModelIndex &left, const QModelIndex &right) const
161 const int compareColumn = left.column();
162 const QVariant leftValue = left.data(TransferListModel::UnderlyingDataRole);
163 const QVariant rightValue = right.data(TransferListModel::UnderlyingDataRole);
165 switch (compareColumn)
167 case TransferListModel::TR_CATEGORY:
168 case TransferListModel::TR_NAME:
169 case TransferListModel::TR_SAVE_PATH:
170 case TransferListModel::TR_TRACKER:
171 return m_naturalCompare(leftValue.toString(), rightValue.toString());
173 case TransferListModel::TR_TAGS:
174 return customCompare(leftValue.value<TagSet>(), rightValue.value<TagSet>(), m_naturalCompare);
176 case TransferListModel::TR_AMOUNT_DOWNLOADED:
177 case TransferListModel::TR_AMOUNT_DOWNLOADED_SESSION:
178 case TransferListModel::TR_AMOUNT_LEFT:
179 case TransferListModel::TR_AMOUNT_UPLOADED:
180 case TransferListModel::TR_AMOUNT_UPLOADED_SESSION:
181 case TransferListModel::TR_COMPLETED:
182 case TransferListModel::TR_ETA:
183 case TransferListModel::TR_LAST_ACTIVITY:
184 case TransferListModel::TR_SIZE:
185 case TransferListModel::TR_TIME_ELAPSED:
186 case TransferListModel::TR_TOTAL_SIZE:
187 return customCompare(leftValue.toLongLong(), rightValue.toLongLong());
189 case TransferListModel::TR_AVAILABILITY:
190 case TransferListModel::TR_PROGRESS:
191 case TransferListModel::TR_RATIO:
192 case TransferListModel::TR_RATIO_LIMIT:
193 return customCompare(leftValue.toReal(), rightValue.toReal());
195 case TransferListModel::TR_STATUS:
196 return threeWayCompare(leftValue.toInt(), rightValue.toInt());
198 case TransferListModel::TR_ADD_DATE:
199 case TransferListModel::TR_SEED_DATE:
200 case TransferListModel::TR_SEEN_COMPLETE_DATE:
201 return customCompare(leftValue.toDateTime(), rightValue.toDateTime());
203 case TransferListModel::TR_DLLIMIT:
204 case TransferListModel::TR_DLSPEED:
205 case TransferListModel::TR_QUEUE_POSITION:
206 case TransferListModel::TR_UPLIMIT:
207 case TransferListModel::TR_UPSPEED:
208 return customCompare(leftValue.toInt(), rightValue.toInt());
210 case TransferListModel::TR_PEERS:
211 case TransferListModel::TR_SEEDS:
213 // Active peers/seeds take precedence over total peers/seeds
214 const auto activeL = leftValue.toInt();
215 const auto activeR = rightValue.toInt();
216 if (activeL != activeR)
217 return threeWayCompare(activeL, activeR);
219 const auto totalL = left.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
220 const auto totalR = right.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
221 return threeWayCompare(totalL, totalR);
224 default:
225 Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparsion case");
226 break;
229 return 0;
232 bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
234 Q_ASSERT(left.column() == right.column());
236 const int result = compare(left, right);
237 if (result == 0)
239 const int subResult = compare(left.sibling(left.row(), m_subSortColumn), right.sibling(right.row(), m_subSortColumn));
240 // Qt inverses lessThan() result when ordered descending.
241 // For sub-sorting we have to do it manually.
242 // When both are ordered descending subResult must be double-inversed, which is the same as no inversion.
243 const bool inverseSubResult = (m_lastSortOrder != m_subSortOrder); // exactly one is descending
244 return (inverseSubResult ? (subResult > 0) : (subResult < 0));
247 return result < 0;
250 bool TransferListSortModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
252 return matchFilter(sourceRow, sourceParent)
253 && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
256 bool TransferListSortModel::matchFilter(const int sourceRow, const QModelIndex &sourceParent) const
258 const auto *model = qobject_cast<TransferListModel *>(sourceModel());
259 if (!model) return false;
261 const BitTorrent::Torrent *torrent = model->torrentHandle(model->index(sourceRow, 0, sourceParent));
262 if (!torrent) return false;
264 return m_filter.match(torrent);