]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistselectionmanager.cpp
Merge branch 'frameworks'
[dolphin.git] / src / kitemviews / kitemlistselectionmanager.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * Copyright (C) 2011 by Frank Reininghaus <frank78ac@googlemail.com> *
4 * *
5 * Based on the Itemviews NG project from Trolltech Labs: *
6 * http://qt.gitorious.org/qt-labs/itemviews-ng *
7 * *
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. *
12 * *
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. *
17 * *
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 ***************************************************************************/
23
24 #include "kitemlistselectionmanager.h"
25
26 #include "kitemmodelbase.h"
27
28 KItemListSelectionManager::KItemListSelectionManager(QObject* parent) :
29 QObject(parent),
30 m_currentItem(-1),
31 m_anchorItem(-1),
32 m_selectedItems(),
33 m_isAnchoredSelectionActive(false),
34 m_model(0)
35 {
36 }
37
38 KItemListSelectionManager::~KItemListSelectionManager()
39 {
40 }
41
42 void KItemListSelectionManager::setCurrentItem(int current)
43 {
44 const int previous = m_currentItem;
45 const KItemSet previousSelection = selectedItems();
46
47 if (m_model && current >= 0 && current < m_model->count()) {
48 m_currentItem = current;
49 } else {
50 m_currentItem = -1;
51 }
52
53 if (m_currentItem != previous) {
54 emit currentChanged(m_currentItem, previous);
55
56 if (m_isAnchoredSelectionActive) {
57 const KItemSet selection = selectedItems();
58 if (selection != previousSelection) {
59 emit selectionChanged(selection, previousSelection);
60 }
61 }
62 }
63 }
64
65 int KItemListSelectionManager::currentItem() const
66 {
67 return m_currentItem;
68 }
69
70 void KItemListSelectionManager::setSelectedItems(const KItemSet& items)
71 {
72 if (m_selectedItems != items) {
73 const KItemSet previous = m_selectedItems;
74 m_selectedItems = items;
75 emit selectionChanged(m_selectedItems, previous);
76 }
77 }
78
79 KItemSet KItemListSelectionManager::selectedItems() const
80 {
81 KItemSet selectedItems = m_selectedItems;
82
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);
88
89 for (int index = from; index <= to; ++index) {
90 selectedItems.insert(index);
91 }
92 }
93
94 return selectedItems;
95 }
96
97 bool KItemListSelectionManager::isSelected(int index) const
98 {
99 if (m_selectedItems.contains(index)) {
100 return true;
101 }
102
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);
108
109 if (from <= index && index <= to) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 bool KItemListSelectionManager::hasSelection() const
118 {
119 return !m_selectedItems.isEmpty() || (m_isAnchoredSelectionActive && m_anchorItem != m_currentItem);
120 }
121
122 void KItemListSelectionManager::setSelected(int index, int count, SelectionMode mode)
123 {
124 if (index < 0 || count < 1 || !m_model || index >= m_model->count()) {
125 return;
126 }
127
128 endAnchoredSelection();
129 const KItemSet previous = selectedItems();
130
131 count = qMin(count, m_model->count() - index);
132
133 const int endIndex = index + count -1;
134 switch (mode) {
135 case Select:
136 for (int i = index; i <= endIndex; ++i) {
137 m_selectedItems.insert(i);
138 }
139 break;
140
141 case Deselect:
142 for (int i = index; i <= endIndex; ++i) {
143 m_selectedItems.remove(i);
144 }
145 break;
146
147 case Toggle:
148 for (int i = index; i <= endIndex; ++i) {
149 if (m_selectedItems.contains(i)) {
150 m_selectedItems.remove(i);
151 } else {
152 m_selectedItems.insert(i);
153 }
154 }
155 break;
156
157 default:
158 Q_ASSERT(false);
159 break;
160 }
161
162 const KItemSet selection = selectedItems();
163 if (selection != previous) {
164 emit selectionChanged(selection, previous);
165 }
166 }
167
168 void KItemListSelectionManager::clearSelection()
169 {
170 const KItemSet previous = selectedItems();
171 if (!previous.isEmpty()) {
172 m_selectedItems.clear();
173 m_isAnchoredSelectionActive = false;
174 emit selectionChanged(KItemSet(), previous);
175 }
176 }
177
178 void KItemListSelectionManager::beginAnchoredSelection(int anchor)
179 {
180 if (anchor >= 0 && m_model && anchor < m_model->count()) {
181 m_isAnchoredSelectionActive = true;
182 m_anchorItem = anchor;
183 }
184 }
185
186 void KItemListSelectionManager::endAnchoredSelection()
187 {
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);
193
194 for (int index = from; index <= to; ++index) {
195 m_selectedItems.insert(index);
196 }
197 }
198
199 m_isAnchoredSelectionActive = false;
200 }
201
202 bool KItemListSelectionManager::isAnchoredSelectionActive() const
203 {
204 return m_isAnchoredSelectionActive;
205 }
206
207 KItemModelBase* KItemListSelectionManager::model() const
208 {
209 return m_model;
210 }
211
212 void KItemListSelectionManager::setModel(KItemModelBase* model)
213 {
214 m_model = model;
215 if (model && model->count() > 0) {
216 m_currentItem = 0;
217 }
218 }
219
220 void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges)
221 {
222 // Store the current selection (needed in the selectionChanged() signal)
223 const KItemSet previousSelection = selectedItems();
224
225 // Update the current item
226 if (m_currentItem < 0) {
227 setCurrentItem(0);
228 } else {
229 const int previousCurrent = m_currentItem;
230 int inc = 0;
231 foreach (const KItemRange& itemRange, itemRanges) {
232 if (m_currentItem < itemRange.index) {
233 break;
234 }
235 inc += itemRange.count;
236 }
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);
241 }
242
243 // Update the anchor item
244 if (m_anchorItem < 0) {
245 m_anchorItem = 0;
246 } else {
247 int inc = 0;
248 foreach (const KItemRange& itemRange, itemRanges) {
249 if (m_anchorItem < itemRange.index) {
250 break;
251 }
252 inc += itemRange.count;
253 }
254 m_anchorItem += inc;
255 }
256
257 // Update the selections
258 if (!m_selectedItems.isEmpty()) {
259 const KItemSet previous = m_selectedItems;
260 m_selectedItems.clear();
261
262 foreach (int index, previous) {
263 int inc = 0;
264 foreach (const KItemRange& itemRange, itemRanges) {
265 if (index < itemRange.index) {
266 break;
267 }
268 inc += itemRange.count;
269 }
270 m_selectedItems.insert(index + inc);
271 }
272 }
273
274 const KItemSet selection = selectedItems();
275 if (selection != previousSelection) {
276 emit selectionChanged(selection, previousSelection);
277 }
278 }
279
280 void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges)
281 {
282 // Store the current selection (needed in the selectionChanged() signal)
283 const KItemSet previousSelection = selectedItems();
284 const int previousCurrent = m_currentItem;
285
286 // Update the current item
287 m_currentItem = indexAfterRangesRemoving(m_currentItem, itemRanges, DiscardRemovedIndex);
288 if (m_currentItem != previousCurrent) {
289 emit currentChanged(m_currentItem, previousCurrent);
290 if (m_currentItem < 0) {
291 // Calling setCurrentItem() would trigger the selectionChanged signal, but we want to
292 // emit it only once in this function -> change the current item manually and emit currentChanged
293 m_currentItem = indexAfterRangesRemoving(previousCurrent, itemRanges, AdjustRemovedIndex);
294 emit currentChanged(m_currentItem, -1);
295 }
296 }
297
298 // Update the anchor item
299 if (m_anchorItem >= 0) {
300 m_anchorItem = indexAfterRangesRemoving(m_anchorItem, itemRanges, DiscardRemovedIndex);
301 if (m_anchorItem < 0) {
302 m_isAnchoredSelectionActive = false;
303 }
304 }
305
306 // Update the selections and the anchor item
307 if (!m_selectedItems.isEmpty()) {
308 const KItemSet previous = m_selectedItems;
309 m_selectedItems.clear();
310
311 foreach (int oldIndex, previous) {
312 const int index = indexAfterRangesRemoving(oldIndex, itemRanges, DiscardRemovedIndex);
313 if (index >= 0) {
314 m_selectedItems.insert(index);
315 }
316 }
317 }
318
319 const KItemSet selection = selectedItems();
320 if (selection != previousSelection) {
321 emit selectionChanged(selection, previousSelection);
322 }
323
324 Q_ASSERT(m_currentItem < m_model->count());
325 Q_ASSERT(m_anchorItem < m_model->count());
326 }
327
328 void KItemListSelectionManager::itemsMoved(const KItemRange& itemRange, const QList<int>& movedToIndexes)
329 {
330 // Store the current selection (needed in the selectionChanged() signal)
331 const KItemSet previousSelection = selectedItems();
332
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();
337
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);
342
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 emit currentChanged(newCurrentItem, previousCurrentItem);
347 }
348
349 // Start a new anchored selection.
350 beginAnchoredSelection(m_currentItem);
351
352 // Update the selections
353 if (!m_selectedItems.isEmpty()) {
354 const KItemSet previous = m_selectedItems;
355 m_selectedItems.clear();
356
357 foreach (int index, previous) {
358 if (index >= itemRange.index && index < itemRange.index + itemRange.count) {
359 m_selectedItems.insert(movedToIndexes.at(index - itemRange.index));
360 }
361 else {
362 m_selectedItems.insert(index);
363 }
364 }
365 }
366
367 const KItemSet selection = selectedItems();
368 if (selection != previousSelection) {
369 emit selectionChanged(selection, previousSelection);
370 }
371 }
372
373 int KItemListSelectionManager::indexAfterRangesRemoving(int index, const KItemRangeList& itemRanges,
374 const RangesRemovingBehaviour behaviour) const
375 {
376 int dec = 0;
377 foreach (const KItemRange& itemRange, itemRanges) {
378 if (index < itemRange.index) {
379 break;
380 }
381
382 dec += itemRange.count;
383
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) {
388 return -1;
389 } else {
390 // Use the first item after the range as new index
391 index = firstIndexAfterRange;
392 break;
393 }
394 }
395 }
396 return qBound(-1, index - dec, m_model->count() - 1);
397 }
398