2 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
3 * SPDX-FileCopyrightText: 2011 Frank Reininghaus <frank78ac@googlemail.com>
5 * Based on the Itemviews NG project from Trolltech Labs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "kitemlistselectionmanager.h"
12 KItemListSelectionManager::KItemListSelectionManager(QObject
*parent
)
17 , m_isAnchoredSelectionActive(false)
22 KItemListSelectionManager::~KItemListSelectionManager()
26 void KItemListSelectionManager::setCurrentItem(int current
)
28 const int previous
= m_currentItem
;
29 const KItemSet previousSelection
= selectedItems();
31 if (m_model
&& current
>= 0 && current
< m_model
->count()) {
32 m_currentItem
= current
;
37 if (m_currentItem
!= previous
) {
38 Q_EMIT
currentChanged(m_currentItem
, previous
);
40 if (m_isAnchoredSelectionActive
) {
41 const KItemSet selection
= selectedItems();
42 if (selection
!= previousSelection
) {
43 Q_EMIT
selectionChanged(selection
, previousSelection
);
49 int KItemListSelectionManager::currentItem() const
54 void KItemListSelectionManager::setSelectedItems(const KItemSet
&items
)
56 if (m_selectedItems
!= items
) {
57 const KItemSet previous
= m_selectedItems
;
58 m_selectedItems
= items
;
59 Q_EMIT
selectionChanged(m_selectedItems
, previous
);
63 KItemSet
KItemListSelectionManager::selectedItems() const
65 KItemSet selectedItems
= m_selectedItems
;
67 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
68 Q_ASSERT(m_anchorItem
>= 0);
69 Q_ASSERT(m_currentItem
>= 0);
70 const int from
= qMin(m_anchorItem
, m_currentItem
);
71 const int to
= qMax(m_anchorItem
, m_currentItem
);
73 for (int index
= from
; index
<= to
; ++index
) {
74 selectedItems
.insert(index
);
81 bool KItemListSelectionManager::isSelected(int index
) const
83 if (m_selectedItems
.contains(index
)) {
87 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
88 Q_ASSERT(m_anchorItem
>= 0);
89 Q_ASSERT(m_currentItem
>= 0);
90 const int from
= qMin(m_anchorItem
, m_currentItem
);
91 const int to
= qMax(m_anchorItem
, m_currentItem
);
93 if (from
<= index
&& index
<= to
) {
101 bool KItemListSelectionManager::hasSelection() const
103 return !m_selectedItems
.isEmpty() || (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
);
106 void KItemListSelectionManager::setSelected(int index
, int count
, SelectionMode mode
)
108 if (index
< 0 || count
< 1 || !m_model
|| index
>= m_model
->count()) {
112 endAnchoredSelection();
113 const KItemSet previous
= selectedItems();
115 count
= qMin(count
, m_model
->count() - index
);
117 const int endIndex
= index
+ count
- 1;
120 for (int i
= index
; i
<= endIndex
; ++i
) {
121 m_selectedItems
.insert(i
);
126 for (int i
= index
; i
<= endIndex
; ++i
) {
127 m_selectedItems
.remove(i
);
132 for (int i
= index
; i
<= endIndex
; ++i
) {
133 if (m_selectedItems
.contains(i
)) {
134 m_selectedItems
.remove(i
);
136 m_selectedItems
.insert(i
);
146 const KItemSet selection
= selectedItems();
147 if (selection
!= previous
) {
148 Q_EMIT
selectionChanged(selection
, previous
);
152 void KItemListSelectionManager::clearSelection()
154 const KItemSet previous
= selectedItems();
155 if (!previous
.isEmpty()) {
156 m_selectedItems
.clear();
157 m_isAnchoredSelectionActive
= false;
158 Q_EMIT
selectionChanged(KItemSet(), previous
);
162 void KItemListSelectionManager::replaceSelection(int index
, int count
)
164 const KItemSet previous
= selectedItems();
165 if (!previous
.isEmpty()) {
166 m_selectedItems
.clear();
167 m_isAnchoredSelectionActive
= false;
169 setSelected(index
, count
);
172 void KItemListSelectionManager::beginAnchoredSelection(int anchor
)
174 if (anchor
>= 0 && m_model
&& anchor
< m_model
->count()) {
175 m_isAnchoredSelectionActive
= true;
176 m_anchorItem
= anchor
;
180 void KItemListSelectionManager::endAnchoredSelection()
182 if (m_isAnchoredSelectionActive
&& (m_anchorItem
!= m_currentItem
)) {
183 Q_ASSERT(m_anchorItem
>= 0);
184 Q_ASSERT(m_currentItem
>= 0);
185 const int from
= qMin(m_anchorItem
, m_currentItem
);
186 const int to
= qMax(m_anchorItem
, m_currentItem
);
188 for (int index
= from
; index
<= to
; ++index
) {
189 m_selectedItems
.insert(index
);
193 m_isAnchoredSelectionActive
= false;
196 bool KItemListSelectionManager::isAnchoredSelectionActive() const
198 return m_isAnchoredSelectionActive
;
201 KItemModelBase
*KItemListSelectionManager::model() const
206 void KItemListSelectionManager::setModel(KItemModelBase
*model
)
209 if (model
&& model
->count() > 0) {
214 void KItemListSelectionManager::itemsInserted(const KItemRangeList
&itemRanges
)
216 // Store the current selection (needed in the selectionChanged() signal)
217 const KItemSet previousSelection
= selectedItems();
219 // Update the current item
220 if (m_currentItem
< 0) {
223 const int previousCurrent
= m_currentItem
;
225 for (const KItemRange
&itemRange
: itemRanges
) {
226 if (m_currentItem
< itemRange
.index
) {
229 inc
+= itemRange
.count
;
231 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
232 // emit it only once in this function -> change the current item manually and emit currentChanged
233 m_currentItem
+= inc
;
234 if (m_currentItem
>= m_model
->count()) {
237 Q_EMIT
currentChanged(m_currentItem
, previousCurrent
);
240 // Update the anchor item
241 if (m_anchorItem
< 0) {
245 for (const KItemRange
&itemRange
: itemRanges
) {
246 if (m_anchorItem
< itemRange
.index
) {
249 inc
+= itemRange
.count
;
254 // Update the selections
255 if (!m_selectedItems
.isEmpty()) {
256 const KItemSet previous
= m_selectedItems
;
257 m_selectedItems
.clear();
259 for (int index
: previous
) {
261 for (const KItemRange
&itemRange
: itemRanges
) {
262 if (index
< itemRange
.index
) {
265 inc
+= itemRange
.count
;
267 m_selectedItems
.insert(index
+ inc
);
271 const KItemSet selection
= selectedItems();
272 if (selection
!= previousSelection
) {
273 Q_EMIT
selectionChanged(selection
, previousSelection
);
277 void KItemListSelectionManager::itemsRemoved(const KItemRangeList
&itemRanges
)
279 // Store the current selection (needed in the selectionChanged() signal)
280 const KItemSet previousSelection
= selectedItems();
281 const int previousCurrent
= m_currentItem
;
283 // Update the current item
284 m_currentItem
= indexAfterRangesRemoving(m_currentItem
, itemRanges
, DiscardRemovedIndex
);
285 if (m_currentItem
!= previousCurrent
) {
286 Q_EMIT
currentChanged(m_currentItem
, previousCurrent
);
287 if (m_currentItem
< 0) {
288 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
289 // emit it only once in this function -> change the current item manually and emit currentChanged
290 m_currentItem
= indexAfterRangesRemoving(previousCurrent
, itemRanges
, AdjustRemovedIndex
);
291 Q_EMIT
currentChanged(m_currentItem
, -1);
295 // Update the anchor item
296 if (m_anchorItem
>= 0) {
297 m_anchorItem
= indexAfterRangesRemoving(m_anchorItem
, itemRanges
, DiscardRemovedIndex
);
298 if (m_anchorItem
< 0) {
299 m_isAnchoredSelectionActive
= false;
303 // Update the selections and the anchor item
304 if (!m_selectedItems
.isEmpty()) {
305 const KItemSet previous
= m_selectedItems
;
306 m_selectedItems
.clear();
308 for (int oldIndex
: previous
) {
309 const int index
= indexAfterRangesRemoving(oldIndex
, itemRanges
, DiscardRemovedIndex
);
311 m_selectedItems
.insert(index
);
316 const KItemSet selection
= selectedItems();
317 if (selection
!= previousSelection
) {
318 Q_EMIT
selectionChanged(selection
, previousSelection
);
321 Q_ASSERT(m_currentItem
< m_model
->count());
322 Q_ASSERT(m_anchorItem
< m_model
->count());
325 void KItemListSelectionManager::itemsMoved(const KItemRange
&itemRange
, const QList
<int> &movedToIndexes
)
327 // Store the current selection (needed in the selectionChanged() signal)
328 const KItemSet previousSelection
= selectedItems();
330 // Store whether we were doing an anchored selection
331 const bool wasInAnchoredSelection
= isAnchoredSelectionActive();
333 // endAnchoredSelection() adds all items between m_currentItem and
334 // m_anchorItem to m_selectedItems. They can then be moved
335 // individually later in this function.
336 endAnchoredSelection();
338 // Update the current item
339 if (m_currentItem
>= itemRange
.index
&& m_currentItem
< itemRange
.index
+ itemRange
.count
) {
340 const int previousCurrentItem
= m_currentItem
;
341 const int newCurrentItem
= movedToIndexes
.at(previousCurrentItem
- itemRange
.index
);
343 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
344 // emit it only once in this function -> change the current item manually and emit currentChanged
345 m_currentItem
= newCurrentItem
;
346 Q_EMIT
currentChanged(newCurrentItem
, previousCurrentItem
);
349 // Start a new anchored selection.
350 if (wasInAnchoredSelection
) {
351 beginAnchoredSelection(m_currentItem
);
354 // Update the selections
355 if (!m_selectedItems
.isEmpty()) {
356 const KItemSet previous
= m_selectedItems
;
357 m_selectedItems
.clear();
359 for (int index
: previous
) {
360 if (index
>= itemRange
.index
&& index
< itemRange
.index
+ itemRange
.count
) {
361 m_selectedItems
.insert(movedToIndexes
.at(index
- itemRange
.index
));
363 m_selectedItems
.insert(index
);
368 const KItemSet selection
= selectedItems();
369 if (selection
!= previousSelection
) {
370 Q_EMIT
selectionChanged(selection
, previousSelection
);
374 int KItemListSelectionManager::indexAfterRangesRemoving(int index
, const KItemRangeList
&itemRanges
, const RangesRemovingBehaviour behaviour
) const
377 for (const KItemRange
&itemRange
: itemRanges
) {
378 if (index
< itemRange
.index
) {
382 dec
+= itemRange
.count
;
384 const int firstIndexAfterRange
= itemRange
.index
+ itemRange
.count
;
385 if (index
< firstIndexAfterRange
) {
386 // The index is part of the removed range
387 if (behaviour
== DiscardRemovedIndex
) {
390 // Use the first item after the range as new index
391 index
= firstIndexAfterRange
;
396 return qBound(-1, index
- dec
, m_model
->count() - 1);
399 #include "moc_kitemlistselectionmanager.cpp"