Don't overwrite stored layout of main window with incorrect one
[qBittorrent.git] / src / gui / transferlistsortmodel.cpp
blob2f9ce6ff09ecc4dc24d9810c1f144bb089d096fe
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->toString(), rightIter->toString());
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(const TorrentFilter::Type filter)
117 if (m_filter.setType(filter))
118 invalidateRowsFilter();
121 void TransferListSortModel::setCategoryFilter(const QString &category)
123 if (m_filter.setCategory(category))
124 invalidateRowsFilter();
127 void TransferListSortModel::disableCategoryFilter()
129 if (m_filter.setCategory(TorrentFilter::AnyCategory))
130 invalidateRowsFilter();
133 void TransferListSortModel::setTagFilter(const Tag &tag)
135 if (m_filter.setTag(tag))
136 invalidateRowsFilter();
139 void TransferListSortModel::disableTagFilter()
141 if (m_filter.setTag(TorrentFilter::AnyTag))
142 invalidateRowsFilter();
145 void TransferListSortModel::setTrackerFilter(const QSet<BitTorrent::TorrentID> &torrentIDs)
147 if (m_filter.setTorrentIDSet(torrentIDs))
148 invalidateRowsFilter();
151 void TransferListSortModel::disableTrackerFilter()
153 if (m_filter.setTorrentIDSet(TorrentFilter::AnyID))
154 invalidateRowsFilter();
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_REANNOUNCE:
190 case TransferListModel::TR_SIZE:
191 case TransferListModel::TR_TIME_ELAPSED:
192 case TransferListModel::TR_TOTAL_SIZE:
193 return customCompare(leftValue.toLongLong(), rightValue.toLongLong());
195 case TransferListModel::TR_AVAILABILITY:
196 case TransferListModel::TR_PROGRESS:
197 case TransferListModel::TR_RATIO:
198 case TransferListModel::TR_RATIO_LIMIT:
199 case TransferListModel::TR_POPULARITY:
200 return customCompare(leftValue.toReal(), rightValue.toReal());
202 case TransferListModel::TR_STATUS:
203 return threeWayCompare(leftValue.toInt(), rightValue.toInt());
205 case TransferListModel::TR_ADD_DATE:
206 case TransferListModel::TR_SEED_DATE:
207 case TransferListModel::TR_SEEN_COMPLETE_DATE:
208 return customCompare(leftValue.toDateTime(), rightValue.toDateTime());
210 case TransferListModel::TR_DLLIMIT:
211 case TransferListModel::TR_DLSPEED:
212 case TransferListModel::TR_QUEUE_POSITION:
213 case TransferListModel::TR_UPLIMIT:
214 case TransferListModel::TR_UPSPEED:
215 return customCompare(leftValue.toInt(), rightValue.toInt());
217 case TransferListModel::TR_PEERS:
218 case TransferListModel::TR_SEEDS:
220 // Active peers/seeds take precedence over total peers/seeds
221 const auto activeL = leftValue.toInt();
222 const auto activeR = rightValue.toInt();
223 if (activeL != activeR)
224 return threeWayCompare(activeL, activeR);
226 const auto totalL = left.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
227 const auto totalR = right.data(TransferListModel::AdditionalUnderlyingDataRole).toInt();
228 return threeWayCompare(totalL, totalR);
231 default:
232 Q_ASSERT_X(false, Q_FUNC_INFO, "Missing comparison case");
233 break;
236 return 0;
239 bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
241 Q_ASSERT(left.column() == right.column());
243 const int result = compare(left, right);
244 if (result == 0)
246 const int subResult = compare(left.sibling(left.row(), m_subSortColumn), right.sibling(right.row(), m_subSortColumn));
247 // Qt inverses lessThan() result when ordered descending.
248 // For sub-sorting we have to do it manually.
249 // When both are ordered descending subResult must be double-inversed, which is the same as no inversion.
250 const bool inverseSubResult = (m_lastSortOrder != m_subSortOrder); // exactly one is descending
251 return (inverseSubResult ? (subResult > 0) : (subResult < 0));
254 return result < 0;
257 bool TransferListSortModel::filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const
259 return matchFilter(sourceRow, sourceParent)
260 && QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
263 bool TransferListSortModel::matchFilter(const int sourceRow, const QModelIndex &sourceParent) const
265 const auto *model = qobject_cast<TransferListModel *>(sourceModel());
266 if (!model) return false;
268 const BitTorrent::Torrent *torrent = model->torrentHandle(model->index(sourceRow, 0, sourceParent));
269 if (!torrent) return false;
271 return m_filter.match(torrent);