1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * Copyright (C) 2011 by Frank Reininghaus <frank78ac@googlemail.com> *
5 * Based on the Itemviews NG project from Trolltech Labs *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
21 ***************************************************************************/
23 #include "kitemlistselectionmanager.h"
25 KItemListSelectionManager::KItemListSelectionManager(QObject
* parent
) :
30 m_isAnchoredSelectionActive(false),
35 KItemListSelectionManager::~KItemListSelectionManager()
39 void KItemListSelectionManager::setCurrentItem(int current
)
41 const int previous
= m_currentItem
;
42 const KItemSet previousSelection
= selectedItems();
44 if (m_model
&& current
>= 0 && current
< m_model
->count()) {
45 m_currentItem
= current
;
50 if (m_currentItem
!= previous
) {
51 emit
currentChanged(m_currentItem
, previous
);
53 if (m_isAnchoredSelectionActive
) {
54 const KItemSet selection
= selectedItems();
55 if (selection
!= previousSelection
) {
56 emit
selectionChanged(selection
, previousSelection
);
62 int KItemListSelectionManager::currentItem() const
67 void KItemListSelectionManager::setSelectedItems(const KItemSet
& items
)
69 if (m_selectedItems
!= items
) {
70 const KItemSet previous
= m_selectedItems
;
71 m_selectedItems
= items
;
72 emit
selectionChanged(m_selectedItems
, previous
);
76 KItemSet
KItemListSelectionManager::selectedItems() const
78 KItemSet selectedItems
= m_selectedItems
;
80 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
81 Q_ASSERT(m_anchorItem
>= 0);
82 Q_ASSERT(m_currentItem
>= 0);
83 const int from
= qMin(m_anchorItem
, m_currentItem
);
84 const int to
= qMax(m_anchorItem
, m_currentItem
);
86 for (int index
= from
; index
<= to
; ++index
) {
87 selectedItems
.insert(index
);
94 bool KItemListSelectionManager::isSelected(int index
) const
96 if (m_selectedItems
.contains(index
)) {
100 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
101 Q_ASSERT(m_anchorItem
>= 0);
102 Q_ASSERT(m_currentItem
>= 0);
103 const int from
= qMin(m_anchorItem
, m_currentItem
);
104 const int to
= qMax(m_anchorItem
, m_currentItem
);
106 if (from
<= index
&& index
<= to
) {
114 bool KItemListSelectionManager::hasSelection() const
116 return !m_selectedItems
.isEmpty() || (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
);
119 void KItemListSelectionManager::setSelected(int index
, int count
, SelectionMode mode
)
121 if (index
< 0 || count
< 1 || !m_model
|| index
>= m_model
->count()) {
125 endAnchoredSelection();
126 const KItemSet previous
= selectedItems();
128 count
= qMin(count
, m_model
->count() - index
);
130 const int endIndex
= index
+ count
-1;
133 for (int i
= index
; i
<= endIndex
; ++i
) {
134 m_selectedItems
.insert(i
);
139 for (int i
= index
; i
<= endIndex
; ++i
) {
140 m_selectedItems
.remove(i
);
145 for (int i
= index
; i
<= endIndex
; ++i
) {
146 if (m_selectedItems
.contains(i
)) {
147 m_selectedItems
.remove(i
);
149 m_selectedItems
.insert(i
);
159 const KItemSet selection
= selectedItems();
160 if (selection
!= previous
) {
161 emit
selectionChanged(selection
, previous
);
165 void KItemListSelectionManager::clearSelection()
167 const KItemSet previous
= selectedItems();
168 if (!previous
.isEmpty()) {
169 m_selectedItems
.clear();
170 m_isAnchoredSelectionActive
= false;
171 emit
selectionChanged(KItemSet(), previous
);
175 void KItemListSelectionManager::replaceSelection(int index
, int count
)
177 const KItemSet previous
= selectedItems();
178 if (!previous
.isEmpty()) {
179 m_selectedItems
.clear();
180 m_isAnchoredSelectionActive
= false;
182 setSelected(index
, count
);
185 void KItemListSelectionManager::beginAnchoredSelection(int anchor
)
187 if (anchor
>= 0 && m_model
&& anchor
< m_model
->count()) {
188 m_isAnchoredSelectionActive
= true;
189 m_anchorItem
= anchor
;
193 void KItemListSelectionManager::endAnchoredSelection()
195 if (m_isAnchoredSelectionActive
&& (m_anchorItem
!= m_currentItem
)) {
196 Q_ASSERT(m_anchorItem
>= 0);
197 Q_ASSERT(m_currentItem
>= 0);
198 const int from
= qMin(m_anchorItem
, m_currentItem
);
199 const int to
= qMax(m_anchorItem
, m_currentItem
);
201 for (int index
= from
; index
<= to
; ++index
) {
202 m_selectedItems
.insert(index
);
206 m_isAnchoredSelectionActive
= false;
209 bool KItemListSelectionManager::isAnchoredSelectionActive() const
211 return m_isAnchoredSelectionActive
;
214 KItemModelBase
* KItemListSelectionManager::model() const
219 void KItemListSelectionManager::setModel(KItemModelBase
* model
)
222 if (model
&& model
->count() > 0) {
227 void KItemListSelectionManager::itemsInserted(const KItemRangeList
& itemRanges
)
229 // Store the current selection (needed in the selectionChanged() signal)
230 const KItemSet previousSelection
= selectedItems();
232 // Update the current item
233 if (m_currentItem
< 0) {
236 const int previousCurrent
= m_currentItem
;
238 foreach (const KItemRange
& itemRange
, itemRanges
) {
239 if (m_currentItem
< itemRange
.index
) {
242 inc
+= itemRange
.count
;
244 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
245 // emit it only once in this function -> change the current item manually and emit currentChanged
246 m_currentItem
+= inc
;
247 if (m_currentItem
>= m_model
->count()) {
250 emit
currentChanged(m_currentItem
, previousCurrent
);
253 // Update the anchor item
254 if (m_anchorItem
< 0) {
258 foreach (const KItemRange
& itemRange
, itemRanges
) {
259 if (m_anchorItem
< itemRange
.index
) {
262 inc
+= itemRange
.count
;
267 // Update the selections
268 if (!m_selectedItems
.isEmpty()) {
269 const KItemSet previous
= m_selectedItems
;
270 m_selectedItems
.clear();
272 for (int index
: previous
) {
274 foreach (const KItemRange
& itemRange
, itemRanges
) {
275 if (index
< itemRange
.index
) {
278 inc
+= itemRange
.count
;
280 m_selectedItems
.insert(index
+ inc
);
284 const KItemSet selection
= selectedItems();
285 if (selection
!= previousSelection
) {
286 emit
selectionChanged(selection
, previousSelection
);
290 void KItemListSelectionManager::itemsRemoved(const KItemRangeList
& itemRanges
)
292 // Store the current selection (needed in the selectionChanged() signal)
293 const KItemSet previousSelection
= selectedItems();
294 const int previousCurrent
= m_currentItem
;
296 // Update the current item
297 m_currentItem
= indexAfterRangesRemoving(m_currentItem
, itemRanges
, DiscardRemovedIndex
);
298 if (m_currentItem
!= previousCurrent
) {
299 emit
currentChanged(m_currentItem
, previousCurrent
);
300 if (m_currentItem
< 0) {
301 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
302 // emit it only once in this function -> change the current item manually and emit currentChanged
303 m_currentItem
= indexAfterRangesRemoving(previousCurrent
, itemRanges
, AdjustRemovedIndex
);
304 emit
currentChanged(m_currentItem
, -1);
308 // Update the anchor item
309 if (m_anchorItem
>= 0) {
310 m_anchorItem
= indexAfterRangesRemoving(m_anchorItem
, itemRanges
, DiscardRemovedIndex
);
311 if (m_anchorItem
< 0) {
312 m_isAnchoredSelectionActive
= false;
316 // Update the selections and the anchor item
317 if (!m_selectedItems
.isEmpty()) {
318 const KItemSet previous
= m_selectedItems
;
319 m_selectedItems
.clear();
321 for (int oldIndex
: previous
) {
322 const int index
= indexAfterRangesRemoving(oldIndex
, itemRanges
, DiscardRemovedIndex
);
324 m_selectedItems
.insert(index
);
329 const KItemSet selection
= selectedItems();
330 if (selection
!= previousSelection
) {
331 emit
selectionChanged(selection
, previousSelection
);
334 Q_ASSERT(m_currentItem
< m_model
->count());
335 Q_ASSERT(m_anchorItem
< m_model
->count());
338 void KItemListSelectionManager::itemsMoved(const KItemRange
& itemRange
, const QList
<int>& movedToIndexes
)
340 // Store the current selection (needed in the selectionChanged() signal)
341 const KItemSet previousSelection
= selectedItems();
343 // Store whether we were doing an anchored selection
344 const bool wasInAnchoredSelection
= isAnchoredSelectionActive();
346 // endAnchoredSelection() adds all items between m_currentItem and
347 // m_anchorItem to m_selectedItems. They can then be moved
348 // individually later in this function.
349 endAnchoredSelection();
351 // Update the current item
352 if (m_currentItem
>= itemRange
.index
&& m_currentItem
< itemRange
.index
+ itemRange
.count
) {
353 const int previousCurrentItem
= m_currentItem
;
354 const int newCurrentItem
= movedToIndexes
.at(previousCurrentItem
- itemRange
.index
);
356 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
357 // emit it only once in this function -> change the current item manually and emit currentChanged
358 m_currentItem
= newCurrentItem
;
359 emit
currentChanged(newCurrentItem
, previousCurrentItem
);
362 // Start a new anchored selection.
363 if (wasInAnchoredSelection
) {
364 beginAnchoredSelection(m_currentItem
);
367 // Update the selections
368 if (!m_selectedItems
.isEmpty()) {
369 const KItemSet previous
= m_selectedItems
;
370 m_selectedItems
.clear();
372 for (int index
: previous
) {
373 if (index
>= itemRange
.index
&& index
< itemRange
.index
+ itemRange
.count
) {
374 m_selectedItems
.insert(movedToIndexes
.at(index
- itemRange
.index
));
377 m_selectedItems
.insert(index
);
382 const KItemSet selection
= selectedItems();
383 if (selection
!= previousSelection
) {
384 emit
selectionChanged(selection
, previousSelection
);
388 int KItemListSelectionManager::indexAfterRangesRemoving(int index
, const KItemRangeList
& itemRanges
,
389 const RangesRemovingBehaviour behaviour
) const
392 foreach (const KItemRange
& itemRange
, itemRanges
) {
393 if (index
< itemRange
.index
) {
397 dec
+= itemRange
.count
;
399 const int firstIndexAfterRange
= itemRange
.index
+ itemRange
.count
;
400 if (index
< firstIndexAfterRange
) {
401 // The index is part of the removed range
402 if (behaviour
== DiscardRemovedIndex
) {
405 // Use the first item after the range as new index
406 index
= firstIndexAfterRange
;
411 return qBound(-1, index
- dec
, m_model
->count() - 1);