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 #include "kitemmodelbase.h"
29 KItemListSelectionManager::KItemListSelectionManager(QObject
* parent
) :
34 m_isAnchoredSelectionActive(false),
39 KItemListSelectionManager::~KItemListSelectionManager()
43 void KItemListSelectionManager::setCurrentItem(int current
)
45 const int previous
= m_currentItem
;
46 const QSet
<int> previousSelection
= selectedItems();
48 if (m_model
&& current
>= 0 && current
< m_model
->count()) {
49 m_currentItem
= current
;
54 if (m_currentItem
!= previous
) {
55 emit
currentChanged(m_currentItem
, previous
);
57 if (m_isAnchoredSelectionActive
) {
58 const QSet
<int> selection
= selectedItems();
59 if (selection
!= previousSelection
) {
60 emit
selectionChanged(selection
, previousSelection
);
66 int KItemListSelectionManager::currentItem() const
71 void KItemListSelectionManager::setSelectedItems(const QSet
<int>& items
)
73 if (m_selectedItems
!= items
) {
74 const QSet
<int> previous
= m_selectedItems
;
75 m_selectedItems
= items
;
76 emit
selectionChanged(m_selectedItems
, previous
);
80 QSet
<int> KItemListSelectionManager::selectedItems() const
82 QSet
<int> selectedItems
= m_selectedItems
;
84 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
85 Q_ASSERT(m_anchorItem
>= 0);
86 Q_ASSERT(m_currentItem
>= 0);
87 const int from
= qMin(m_anchorItem
, m_currentItem
);
88 const int to
= qMax(m_anchorItem
, m_currentItem
);
90 for (int index
= from
; index
<= to
; ++index
) {
91 selectedItems
.insert(index
);
98 bool KItemListSelectionManager::isSelected(int index
) const
100 if (m_selectedItems
.contains(index
)) {
104 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
105 Q_ASSERT(m_anchorItem
>= 0);
106 Q_ASSERT(m_currentItem
>= 0);
107 const int from
= qMin(m_anchorItem
, m_currentItem
);
108 const int to
= qMax(m_anchorItem
, m_currentItem
);
110 if (from
<= index
&& index
<= to
) {
118 bool KItemListSelectionManager::hasSelection() const
120 return !m_selectedItems
.isEmpty() || (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
);
123 void KItemListSelectionManager::setSelected(int index
, int count
, SelectionMode mode
)
125 if (index
< 0 || count
< 1 || !m_model
|| index
>= m_model
->count()) {
129 endAnchoredSelection();
130 const QSet
<int> previous
= selectedItems();
132 count
= qMin(count
, m_model
->count() - index
);
134 const int endIndex
= index
+ count
-1;
137 for (int i
= index
; i
<= endIndex
; ++i
) {
138 m_selectedItems
.insert(i
);
143 for (int i
= index
; i
<= endIndex
; ++i
) {
144 m_selectedItems
.remove(i
);
149 for (int i
= index
; i
<= endIndex
; ++i
) {
150 if (m_selectedItems
.contains(i
)) {
151 m_selectedItems
.remove(i
);
153 m_selectedItems
.insert(i
);
163 const QSet
<int> selection
= selectedItems();
164 if (selection
!= previous
) {
165 emit
selectionChanged(selection
, previous
);
169 void KItemListSelectionManager::clearSelection()
171 const QSet
<int> previous
= selectedItems();
172 if (!previous
.isEmpty()) {
173 m_selectedItems
.clear();
174 m_isAnchoredSelectionActive
= false;
175 emit
selectionChanged(QSet
<int>(), previous
);
179 void KItemListSelectionManager::beginAnchoredSelection(int anchor
)
181 if (anchor
>= 0 && m_model
&& anchor
< m_model
->count()) {
182 m_isAnchoredSelectionActive
= true;
183 m_anchorItem
= anchor
;
187 void KItemListSelectionManager::endAnchoredSelection()
189 if (m_isAnchoredSelectionActive
&& (m_anchorItem
!= m_currentItem
)) {
190 Q_ASSERT(m_anchorItem
>= 0);
191 Q_ASSERT(m_currentItem
>= 0);
192 const int from
= qMin(m_anchorItem
, m_currentItem
);
193 const int to
= qMax(m_anchorItem
, m_currentItem
);
195 for (int index
= from
; index
<= to
; ++index
) {
196 m_selectedItems
.insert(index
);
200 m_isAnchoredSelectionActive
= false;
203 bool KItemListSelectionManager::isAnchoredSelectionActive() const
205 return m_isAnchoredSelectionActive
;
208 KItemModelBase
* KItemListSelectionManager::model() const
213 void KItemListSelectionManager::setModel(KItemModelBase
* model
)
216 if (model
&& model
->count() > 0) {
221 void KItemListSelectionManager::itemsInserted(const KItemRangeList
& itemRanges
)
223 // Store the current selection (needed in the selectionChanged() signal)
224 const QSet
<int> previousSelection
= selectedItems();
226 // Update the current item
227 if (m_currentItem
< 0) {
230 const int previousCurrent
= m_currentItem
;
232 foreach (const KItemRange
& itemRange
, itemRanges
) {
233 if (m_currentItem
< itemRange
.index
) {
236 inc
+= itemRange
.count
;
238 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
239 // emit it only once in this function -> change the current item manually and emit currentChanged
240 m_currentItem
+= inc
;
241 emit
currentChanged(m_currentItem
, previousCurrent
);
244 // Update the anchor item
245 if (m_anchorItem
< 0) {
249 foreach (const KItemRange
& itemRange
, itemRanges
) {
250 if (m_anchorItem
< itemRange
.index
) {
253 inc
+= itemRange
.count
;
258 // Update the selections
259 if (!m_selectedItems
.isEmpty()) {
260 const QSet
<int> previous
= m_selectedItems
;
261 m_selectedItems
.clear();
262 m_selectedItems
.reserve(previous
.count());
263 QSetIterator
<int> it(previous
);
264 while (it
.hasNext()) {
265 const int index
= it
.next();
267 foreach (const KItemRange
& itemRange
, itemRanges
) {
268 if (index
< itemRange
.index
) {
271 inc
+= itemRange
.count
;
273 m_selectedItems
.insert(index
+ inc
);
277 const QSet
<int> selection
= selectedItems();
278 if (selection
!= previousSelection
) {
279 emit
selectionChanged(selection
, previousSelection
);
283 void KItemListSelectionManager::itemsRemoved(const KItemRangeList
& itemRanges
)
285 // Store the current selection (needed in the selectionChanged() signal)
286 const QSet
<int> previousSelection
= selectedItems();
287 const int previousCurrent
= m_currentItem
;
289 // Update the current item
290 m_currentItem
= indexAfterRangesRemoving(m_currentItem
, itemRanges
, DiscardRemovedIndex
);
291 if (m_currentItem
!= previousCurrent
) {
292 emit
currentChanged(m_currentItem
, previousCurrent
);
293 if (m_currentItem
< 0) {
294 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
295 // emit it only once in this function -> change the current item manually and emit currentChanged
296 m_currentItem
= indexAfterRangesRemoving(previousCurrent
, itemRanges
, AdjustRemovedIndex
);
297 emit
currentChanged(m_currentItem
, -1);
301 // Update the anchor item
302 if (m_anchorItem
>= 0) {
303 m_anchorItem
= indexAfterRangesRemoving(m_anchorItem
, itemRanges
, DiscardRemovedIndex
);
304 if (m_anchorItem
< 0) {
305 m_isAnchoredSelectionActive
= false;
309 // Update the selections and the anchor item
310 if (!m_selectedItems
.isEmpty()) {
311 const QSet
<int> previous
= m_selectedItems
;
312 m_selectedItems
.clear();
313 m_selectedItems
.reserve(previous
.count());
314 QSetIterator
<int> it(previous
);
315 while (it
.hasNext()) {
316 const int index
= indexAfterRangesRemoving(it
.next(), itemRanges
, DiscardRemovedIndex
);
318 m_selectedItems
.insert(index
);
323 const QSet
<int> selection
= selectedItems();
324 if (selection
!= previousSelection
) {
325 emit
selectionChanged(selection
, previousSelection
);
328 Q_ASSERT(m_currentItem
< m_model
->count());
329 Q_ASSERT(m_anchorItem
< m_model
->count());
332 void KItemListSelectionManager::itemsMoved(const KItemRange
& itemRange
, const QList
<int>& movedToIndexes
)
334 // Store the current selection (needed in the selectionChanged() signal)
335 const QSet
<int> previousSelection
= selectedItems();
337 // Update the current item
338 if (m_currentItem
>= itemRange
.index
&& m_currentItem
< itemRange
.index
+ itemRange
.count
) {
339 const int previousCurrentItem
= m_currentItem
;
340 const int newCurrentItem
= movedToIndexes
.at(previousCurrentItem
- itemRange
.index
);
342 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
343 // emit it only once in this function -> change the current item manually and emit currentChanged
344 m_currentItem
= newCurrentItem
;
345 emit
currentChanged(newCurrentItem
, previousCurrentItem
);
348 // Update the anchor item
349 if (m_anchorItem
>= itemRange
.index
&& m_anchorItem
< itemRange
.index
+ itemRange
.count
) {
350 m_anchorItem
= movedToIndexes
.at(m_anchorItem
- itemRange
.index
);
353 // Update the selections
354 if (!m_selectedItems
.isEmpty()) {
355 const QSet
<int> previous
= m_selectedItems
;
356 m_selectedItems
.clear();
357 m_selectedItems
.reserve(previous
.count());
358 QSetIterator
<int> it(previous
);
359 while (it
.hasNext()) {
360 const int index
= it
.next();
361 if (index
>= itemRange
.index
&& index
< itemRange
.index
+ itemRange
.count
) {
362 m_selectedItems
.insert(movedToIndexes
.at(index
- itemRange
.index
));
365 m_selectedItems
.insert(index
);
370 const QSet
<int> selection
= selectedItems();
371 if (selection
!= previousSelection
) {
372 emit
selectionChanged(selection
, previousSelection
);
376 int KItemListSelectionManager::indexAfterRangesRemoving(int index
, const KItemRangeList
& itemRanges
,
377 const RangesRemovingBehaviour behaviour
) const
380 foreach (const KItemRange
& itemRange
, itemRanges
) {
381 if (index
< itemRange
.index
) {
385 dec
+= itemRange
.count
;
387 const int firstIndexAfterRange
= itemRange
.index
+ itemRange
.count
;
388 if (index
< firstIndexAfterRange
) {
389 // The index is part of the removed range
390 if (behaviour
== DiscardRemovedIndex
) {
393 // Use the first item after the range as new index
394 index
= firstIndexAfterRange
;
399 return qBound(-1, index
- dec
, m_model
->count() - 1);
401 #include "kitemlistselectionmanager.moc"