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>
35 #include "base/bittorrent/infohash.h"
36 #include "base/bittorrent/torrent.h"
37 #include "transferlistmodel.h"
42 int threeWayCompare(const T
&left
, const T
&right
)
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
)
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
);
71 return threeWayCompare(left
.size(), right
.size());
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
)
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
))
123 void TransferListSortModel::setCategoryFilter(const QString
&category
)
125 if (m_filter
.setCategory(category
))
129 void TransferListSortModel::disableCategoryFilter()
131 if (m_filter
.setCategory(TorrentFilter::AnyCategory
))
135 void TransferListSortModel::setTagFilter(const QString
&tag
)
137 if (m_filter
.setTag(tag
))
141 void TransferListSortModel::disableTagFilter()
143 if (m_filter
.setTag(TorrentFilter::AnyTag
))
147 void TransferListSortModel::setTrackerFilter(const QSet
<BitTorrent::TorrentID
> &torrentIDs
)
149 if (m_filter
.setTorrentIDSet(torrentIDs
))
153 void TransferListSortModel::disableTrackerFilter()
155 if (m_filter
.setTorrentIDSet(TorrentFilter::AnyID
))
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
);
225 Q_ASSERT_X(false, Q_FUNC_INFO
, "Missing comparsion case");
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
);
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));
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
);