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: *
6 * http://qt.gitorious.org/qt-labs/itemviews-ng *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
22 ***************************************************************************/
24 #include "kitemlistselectionmanager.h"
26 KItemListSelectionManager::KItemListSelectionManager(QObject
* parent
) :
31 m_isAnchoredSelectionActive(false),
36 KItemListSelectionManager::~KItemListSelectionManager()
40 void KItemListSelectionManager::setCurrentItem(int current
)
42 const int previous
= m_currentItem
;
43 const KItemSet previousSelection
= selectedItems();
45 if (m_model
&& current
>= 0 && current
< m_model
->count()) {
46 m_currentItem
= current
;
51 if (m_currentItem
!= previous
) {
52 emit
currentChanged(m_currentItem
, previous
);
54 if (m_isAnchoredSelectionActive
) {
55 const KItemSet selection
= selectedItems();
56 if (selection
!= previousSelection
) {
57 emit
selectionChanged(selection
, previousSelection
);
63 int KItemListSelectionManager::currentItem() const
68 void KItemListSelectionManager::setSelectedItems(const KItemSet
& items
)
70 if (m_selectedItems
!= items
) {
71 const KItemSet previous
= m_selectedItems
;
72 m_selectedItems
= items
;
73 emit
selectionChanged(m_selectedItems
, previous
);
77 KItemSet
KItemListSelectionManager::selectedItems() const
79 KItemSet selectedItems
= m_selectedItems
;
81 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
82 Q_ASSERT(m_anchorItem
>= 0);
83 Q_ASSERT(m_currentItem
>= 0);
84 const int from
= qMin(m_anchorItem
, m_currentItem
);
85 const int to
= qMax(m_anchorItem
, m_currentItem
);
87 for (int index
= from
; index
<= to
; ++index
) {
88 selectedItems
.insert(index
);
95 bool KItemListSelectionManager::isSelected(int index
) const
97 if (m_selectedItems
.contains(index
)) {
101 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
102 Q_ASSERT(m_anchorItem
>= 0);
103 Q_ASSERT(m_currentItem
>= 0);
104 const int from
= qMin(m_anchorItem
, m_currentItem
);
105 const int to
= qMax(m_anchorItem
, m_currentItem
);
107 if (from
<= index
&& index
<= to
) {
115 bool KItemListSelectionManager::hasSelection() const
117 return !m_selectedItems
.isEmpty() || (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
);
120 void KItemListSelectionManager::setSelected(int index
, int count
, SelectionMode mode
)
122 if (index
< 0 || count
< 1 || !m_model
|| index
>= m_model
->count()) {
126 endAnchoredSelection();
127 const KItemSet previous
= selectedItems();
129 count
= qMin(count
, m_model
->count() - index
);
131 const int endIndex
= index
+ count
-1;
134 for (int i
= index
; i
<= endIndex
; ++i
) {
135 m_selectedItems
.insert(i
);
140 for (int i
= index
; i
<= endIndex
; ++i
) {
141 m_selectedItems
.remove(i
);
146 for (int i
= index
; i
<= endIndex
; ++i
) {
147 if (m_selectedItems
.contains(i
)) {
148 m_selectedItems
.remove(i
);
150 m_selectedItems
.insert(i
);
160 const KItemSet selection
= selectedItems();
161 if (selection
!= previous
) {
162 emit
selectionChanged(selection
, previous
);
166 void KItemListSelectionManager::clearSelection()
168 const KItemSet previous
= selectedItems();
169 if (!previous
.isEmpty()) {
170 m_selectedItems
.clear();
171 m_isAnchoredSelectionActive
= false;
172 emit
selectionChanged(KItemSet(), previous
);
176 void KItemListSelectionManager::replaceSelection(int index
, int count
)
178 const KItemSet previous
= selectedItems();
179 if (!previous
.isEmpty()) {
180 m_selectedItems
.clear();
181 m_isAnchoredSelectionActive
= false;
183 setSelected(index
, count
);
186 void KItemListSelectionManager::beginAnchoredSelection(int anchor
)
188 if (anchor
>= 0 && m_model
&& anchor
< m_model
->count()) {
189 m_isAnchoredSelectionActive
= true;
190 m_anchorItem
= anchor
;
194 void KItemListSelectionManager::endAnchoredSelection()
196 if (m_isAnchoredSelectionActive
&& (m_anchorItem
!= m_currentItem
)) {
197 Q_ASSERT(m_anchorItem
>= 0);
198 Q_ASSERT(m_currentItem
>= 0);
199 const int from
= qMin(m_anchorItem
, m_currentItem
);
200 const int to
= qMax(m_anchorItem
, m_currentItem
);
202 for (int index
= from
; index
<= to
; ++index
) {
203 m_selectedItems
.insert(index
);
207 m_isAnchoredSelectionActive
= false;
210 bool KItemListSelectionManager::isAnchoredSelectionActive() const
212 return m_isAnchoredSelectionActive
;
215 KItemModelBase
* KItemListSelectionManager::model() const
220 void KItemListSelectionManager::setModel(KItemModelBase
* model
)
223 if (model
&& model
->count() > 0) {
228 void KItemListSelectionManager::itemsInserted(const KItemRangeList
& itemRanges
)
230 // Store the current selection (needed in the selectionChanged() signal)
231 const KItemSet previousSelection
= selectedItems();
233 // Update the current item
234 if (m_currentItem
< 0) {
237 const int previousCurrent
= m_currentItem
;
239 foreach (const KItemRange
& itemRange
, itemRanges
) {
240 if (m_currentItem
< itemRange
.index
) {
243 inc
+= itemRange
.count
;
245 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
246 // emit it only once in this function -> change the current item manually and emit currentChanged
247 m_currentItem
+= inc
;
248 if (m_currentItem
>= m_model
->count()) {
251 emit
currentChanged(m_currentItem
, previousCurrent
);
254 // Update the anchor item
255 if (m_anchorItem
< 0) {
259 foreach (const KItemRange
& itemRange
, itemRanges
) {
260 if (m_anchorItem
< itemRange
.index
) {
263 inc
+= itemRange
.count
;
268 // Update the selections
269 if (!m_selectedItems
.isEmpty()) {
270 const KItemSet previous
= m_selectedItems
;
271 m_selectedItems
.clear();
273 for (int index
: previous
) {
275 foreach (const KItemRange
& itemRange
, itemRanges
) {
276 if (index
< itemRange
.index
) {
279 inc
+= itemRange
.count
;
281 m_selectedItems
.insert(index
+ inc
);
285 const KItemSet selection
= selectedItems();
286 if (selection
!= previousSelection
) {
287 emit
selectionChanged(selection
, previousSelection
);
291 void KItemListSelectionManager::itemsRemoved(const KItemRangeList
& itemRanges
)
293 // Store the current selection (needed in the selectionChanged() signal)
294 const KItemSet previousSelection
= selectedItems();
295 const int previousCurrent
= m_currentItem
;
297 // Update the current item
298 m_currentItem
= indexAfterRangesRemoving(m_currentItem
, itemRanges
, DiscardRemovedIndex
);
299 if (m_currentItem
!= previousCurrent
) {
300 emit
currentChanged(m_currentItem
, previousCurrent
);
301 if (m_currentItem
< 0) {
302 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
303 // emit it only once in this function -> change the current item manually and emit currentChanged
304 m_currentItem
= indexAfterRangesRemoving(previousCurrent
, itemRanges
, AdjustRemovedIndex
);
305 emit
currentChanged(m_currentItem
, -1);
309 // Update the anchor item
310 if (m_anchorItem
>= 0) {
311 m_anchorItem
= indexAfterRangesRemoving(m_anchorItem
, itemRanges
, DiscardRemovedIndex
);
312 if (m_anchorItem
< 0) {
313 m_isAnchoredSelectionActive
= false;
317 // Update the selections and the anchor item
318 if (!m_selectedItems
.isEmpty()) {
319 const KItemSet previous
= m_selectedItems
;
320 m_selectedItems
.clear();
322 for (int oldIndex
: previous
) {
323 const int index
= indexAfterRangesRemoving(oldIndex
, itemRanges
, DiscardRemovedIndex
);
325 m_selectedItems
.insert(index
);
330 const KItemSet selection
= selectedItems();
331 if (selection
!= previousSelection
) {
332 emit
selectionChanged(selection
, previousSelection
);
335 Q_ASSERT(m_currentItem
< m_model
->count());
336 Q_ASSERT(m_anchorItem
< m_model
->count());
339 void KItemListSelectionManager::itemsMoved(const KItemRange
& itemRange
, const QList
<int>& movedToIndexes
)
341 // Store the current selection (needed in the selectionChanged() signal)
342 const KItemSet previousSelection
= selectedItems();
344 // Store whether we were doing an anchored selection
345 const bool wasInAnchoredSelection
= isAnchoredSelectionActive();
347 // endAnchoredSelection() adds all items between m_currentItem and
348 // m_anchorItem to m_selectedItems. They can then be moved
349 // individually later in this function.
350 endAnchoredSelection();
352 // Update the current item
353 if (m_currentItem
>= itemRange
.index
&& m_currentItem
< itemRange
.index
+ itemRange
.count
) {
354 const int previousCurrentItem
= m_currentItem
;
355 const int newCurrentItem
= movedToIndexes
.at(previousCurrentItem
- itemRange
.index
);
357 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
358 // emit it only once in this function -> change the current item manually and emit currentChanged
359 m_currentItem
= newCurrentItem
;
360 emit
currentChanged(newCurrentItem
, previousCurrentItem
);
363 // Start a new anchored selection.
364 if (wasInAnchoredSelection
) {
365 beginAnchoredSelection(m_currentItem
);
368 // Update the selections
369 if (!m_selectedItems
.isEmpty()) {
370 const KItemSet previous
= m_selectedItems
;
371 m_selectedItems
.clear();
373 for (int index
: previous
) {
374 if (index
>= itemRange
.index
&& index
< itemRange
.index
+ itemRange
.count
) {
375 m_selectedItems
.insert(movedToIndexes
.at(index
- itemRange
.index
));
378 m_selectedItems
.insert(index
);
383 const KItemSet selection
= selectedItems();
384 if (selection
!= previousSelection
) {
385 emit
selectionChanged(selection
, previousSelection
);
389 int KItemListSelectionManager::indexAfterRangesRemoving(int index
, const KItemRangeList
& itemRanges
,
390 const RangesRemovingBehaviour behaviour
) const
393 foreach (const KItemRange
& itemRange
, itemRanges
) {
394 if (index
< itemRange
.index
) {
398 dec
+= itemRange
.count
;
400 const int firstIndexAfterRange
= itemRange
.index
+ itemRange
.count
;
401 if (index
< firstIndexAfterRange
) {
402 // The index is part of the removed range
403 if (behaviour
== DiscardRemovedIndex
) {
406 // Use the first item after the range as new index
407 index
= firstIndexAfterRange
;
412 return qBound(-1, index
- dec
, m_model
->count() - 1);