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"
25 #include "kitemmodelbase.h"
28 KItemListSelectionManager::KItemListSelectionManager(QObject
* parent
) :
33 m_isAnchoredSelectionActive(false),
38 KItemListSelectionManager::~KItemListSelectionManager()
42 void KItemListSelectionManager::setCurrentItem(int current
)
44 const int previous
= m_currentItem
;
45 const QSet
<int> previousSelection
= selectedItems();
47 if (m_model
&& current
>= 0 && current
< m_model
->count()) {
48 m_currentItem
= current
;
53 if (m_currentItem
!= previous
) {
54 emit
currentChanged(m_currentItem
, previous
);
56 if (m_isAnchoredSelectionActive
) {
57 const QSet
<int> selection
= selectedItems();
58 if (selection
!= previousSelection
) {
59 emit
selectionChanged(selection
, previousSelection
);
65 int KItemListSelectionManager::currentItem() const
70 void KItemListSelectionManager::setSelectedItems(const QSet
<int>& items
)
72 if (m_selectedItems
!= items
) {
73 const QSet
<int> previous
= m_selectedItems
;
74 m_selectedItems
= items
;
75 emit
selectionChanged(m_selectedItems
, previous
);
79 QSet
<int> KItemListSelectionManager::selectedItems() const
81 QSet
<int> selectedItems
= m_selectedItems
;
83 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
84 Q_ASSERT(m_anchorItem
>= 0);
85 Q_ASSERT(m_currentItem
>= 0);
86 const int from
= qMin(m_anchorItem
, m_currentItem
);
87 const int to
= qMax(m_anchorItem
, m_currentItem
);
89 for (int index
= from
; index
<= to
; ++index
) {
90 selectedItems
.insert(index
);
97 bool KItemListSelectionManager::isSelected(int index
) const
99 if (m_selectedItems
.contains(index
)) {
103 if (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
) {
104 Q_ASSERT(m_anchorItem
>= 0);
105 Q_ASSERT(m_currentItem
>= 0);
106 const int from
= qMin(m_anchorItem
, m_currentItem
);
107 const int to
= qMax(m_anchorItem
, m_currentItem
);
109 if (from
<= index
&& index
<= to
) {
117 bool KItemListSelectionManager::hasSelection() const
119 return !m_selectedItems
.isEmpty() || (m_isAnchoredSelectionActive
&& m_anchorItem
!= m_currentItem
);
122 void KItemListSelectionManager::setSelected(int index
, int count
, SelectionMode mode
)
124 if (index
< 0 || count
< 1 || !m_model
|| index
>= m_model
->count()) {
128 endAnchoredSelection();
129 const QSet
<int> previous
= selectedItems();
131 count
= qMin(count
, m_model
->count() - index
);
133 const int endIndex
= index
+ count
-1;
136 for (int i
= index
; i
<= endIndex
; ++i
) {
137 m_selectedItems
.insert(i
);
142 for (int i
= index
; i
<= endIndex
; ++i
) {
143 m_selectedItems
.remove(i
);
148 for (int i
= index
; i
<= endIndex
; ++i
) {
149 if (m_selectedItems
.contains(i
)) {
150 m_selectedItems
.remove(i
);
152 m_selectedItems
.insert(i
);
162 const QSet
<int> selection
= selectedItems();
163 if (selection
!= previous
) {
164 emit
selectionChanged(selection
, previous
);
168 void KItemListSelectionManager::clearSelection()
170 const QSet
<int> previous
= selectedItems();
171 if (!previous
.isEmpty()) {
172 m_selectedItems
.clear();
173 m_isAnchoredSelectionActive
= false;
174 emit
selectionChanged(QSet
<int>(), previous
);
178 void KItemListSelectionManager::beginAnchoredSelection(int anchor
)
180 if (anchor
>= 0 && m_model
&& anchor
< m_model
->count()) {
181 m_isAnchoredSelectionActive
= true;
182 m_anchorItem
= anchor
;
186 void KItemListSelectionManager::endAnchoredSelection()
188 if (m_isAnchoredSelectionActive
&& (m_anchorItem
!= m_currentItem
)) {
189 Q_ASSERT(m_anchorItem
>= 0);
190 Q_ASSERT(m_currentItem
>= 0);
191 const int from
= qMin(m_anchorItem
, m_currentItem
);
192 const int to
= qMax(m_anchorItem
, m_currentItem
);
194 for (int index
= from
; index
<= to
; ++index
) {
195 m_selectedItems
.insert(index
);
199 m_isAnchoredSelectionActive
= false;
202 bool KItemListSelectionManager::isAnchoredSelectionActive() const
204 return m_isAnchoredSelectionActive
;
207 KItemModelBase
* KItemListSelectionManager::model() const
212 void KItemListSelectionManager::setModel(KItemModelBase
* model
)
215 if (model
&& model
->count() > 0) {
220 void KItemListSelectionManager::itemsInserted(const KItemRangeList
& itemRanges
)
222 // Store the current selection (needed in the selectionChanged() signal)
223 const QSet
<int> previousSelection
= selectedItems();
225 // Update the current item
226 if (m_currentItem
< 0) {
229 const int previousCurrent
= m_currentItem
;
231 foreach (const KItemRange
& itemRange
, itemRanges
) {
232 if (m_currentItem
< itemRange
.index
) {
235 inc
+= itemRange
.count
;
237 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
238 // emit it only once in this function -> change the current item manually and emit currentChanged
239 m_currentItem
+= inc
;
240 emit
currentChanged(m_currentItem
, previousCurrent
);
243 // Update the anchor item
244 if (m_anchorItem
< 0) {
248 foreach (const KItemRange
& itemRange
, itemRanges
) {
249 if (m_anchorItem
< itemRange
.index
) {
252 inc
+= itemRange
.count
;
257 // Update the selections
258 if (!m_selectedItems
.isEmpty()) {
259 const QSet
<int> previous
= m_selectedItems
;
260 m_selectedItems
.clear();
261 m_selectedItems
.reserve(previous
.count());
262 QSetIterator
<int> it(previous
);
263 while (it
.hasNext()) {
264 const int index
= it
.next();
266 foreach (const KItemRange
& itemRange
, itemRanges
) {
267 if (index
< itemRange
.index
) {
270 inc
+= itemRange
.count
;
272 m_selectedItems
.insert(index
+ inc
);
276 const QSet
<int> selection
= selectedItems();
277 if (selection
!= previousSelection
) {
278 emit
selectionChanged(selection
, previousSelection
);
282 void KItemListSelectionManager::itemsRemoved(const KItemRangeList
& itemRanges
)
284 // Store the current selection (needed in the selectionChanged() signal)
285 const QSet
<int> previousSelection
= selectedItems();
287 // Update the current item
288 if (m_currentItem
>= 0) {
289 const int previousCurrent
= m_currentItem
;
290 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
291 // emit it only once in this function -> change the current item manually and emit currentChanged
292 m_currentItem
= indexAfterRangesRemoving(m_currentItem
, itemRanges
);
293 if (m_currentItem
!= previousCurrent
) {
294 emit
currentChanged(m_currentItem
, previousCurrent
);
297 if (m_currentItem
< 0) {
298 // The current item has been removed.
299 m_currentItem
= qMin(previousCurrent
, m_model
->count() - 1);
300 emit
currentChanged(m_currentItem
, -1);
304 // Update the anchor item
305 if (m_anchorItem
>= 0) {
306 m_anchorItem
= indexAfterRangesRemoving(m_anchorItem
, itemRanges
);
307 if (m_anchorItem
< 0) {
308 m_isAnchoredSelectionActive
= false;
312 // Update the selections and the anchor item
313 if (!m_selectedItems
.isEmpty()) {
314 const QSet
<int> previous
= m_selectedItems
;
315 m_selectedItems
.clear();
316 m_selectedItems
.reserve(previous
.count());
317 QSetIterator
<int> it(previous
);
318 while (it
.hasNext()) {
319 const int index
= indexAfterRangesRemoving(it
.next(), itemRanges
);
321 m_selectedItems
.insert(index
);
326 const QSet
<int> selection
= selectedItems();
327 if (selection
!= previousSelection
) {
328 emit
selectionChanged(selection
, previousSelection
);
331 Q_ASSERT(m_currentItem
< m_model
->count());
332 Q_ASSERT(m_anchorItem
< m_model
->count());
335 void KItemListSelectionManager::itemsMoved(const KItemRange
& itemRange
, const QList
<int>& movedToIndexes
)
337 // Store the current selection (needed in the selectionChanged() signal)
338 const QSet
<int> previousSelection
= selectedItems();
340 // Update the current item
341 if (m_currentItem
>= itemRange
.index
&& m_currentItem
< itemRange
.index
+ itemRange
.count
) {
342 const int previousCurrentItem
= m_currentItem
;
343 const int newCurrentItem
= movedToIndexes
.at(previousCurrentItem
- itemRange
.index
);
345 // Calling setCurrentItem would trigger the selectionChanged signal, but we want to
346 // emit it only once in this function -> change the current item manually and emit currentChanged
347 m_currentItem
= newCurrentItem
;
348 emit
currentChanged(newCurrentItem
, previousCurrentItem
);
351 // Update the anchor item
352 if (m_anchorItem
>= itemRange
.index
&& m_anchorItem
< itemRange
.index
+ itemRange
.count
) {
353 m_anchorItem
= movedToIndexes
.at(m_anchorItem
- itemRange
.index
);
356 // Update the selections
357 if (!m_selectedItems
.isEmpty()) {
358 const QSet
<int> previous
= m_selectedItems
;
359 m_selectedItems
.clear();
360 m_selectedItems
.reserve(previous
.count());
361 QSetIterator
<int> it(previous
);
362 while (it
.hasNext()) {
363 const int index
= it
.next();
364 if (index
>= itemRange
.index
&& index
< itemRange
.index
+ itemRange
.count
) {
365 m_selectedItems
.insert(movedToIndexes
.at(index
- itemRange
.index
));
368 m_selectedItems
.insert(index
);
373 const QSet
<int> selection
= selectedItems();
374 if (selection
!= previousSelection
) {
375 emit
selectionChanged(selection
, previousSelection
);
379 int KItemListSelectionManager::indexAfterRangesRemoving(int index
, const KItemRangeList
& itemRanges
) const
382 foreach (const KItemRange
& itemRange
, itemRanges
) {
383 if (index
< itemRange
.index
) {
387 if (index
< itemRange
.index
+ itemRange
.count
) {
388 // The index is part of the removed range
392 dec
+= itemRange
.count
;
396 #include "kitemlistselectionmanager.moc"