]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistselectionmanager.cpp
Initial support for anchored selections in the selection manager
[dolphin.git] / src / kitemviews / kitemlistselectionmanager.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * Based on the Itemviews NG project from Trolltech Labs: *
5 * http://qt.gitorious.org/qt-labs/itemviews-ng *
6 * *
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. *
11 * *
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. *
16 * *
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 ***************************************************************************/
22
23 #include "kitemlistselectionmanager.h"
24
25 #include "kitemmodelbase.h"
26 #include <KDebug>
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_anchoredSelectionMode(KItemListSelectionManager::Select),
35 m_model(0)
36 {
37 }
38
39 KItemListSelectionManager::~KItemListSelectionManager()
40 {
41 }
42
43 void KItemListSelectionManager::setCurrentItem(int current)
44 {
45 const int previous = m_currentItem;
46 if (m_model && current >= 0 && current < m_model->count()) {
47 m_currentItem = current;
48 } else {
49 m_currentItem = -1;
50 }
51
52 if (m_currentItem != previous) {
53 emit currentChanged(m_currentItem, previous);
54 }
55 }
56
57 int KItemListSelectionManager::currentItem() const
58 {
59 return m_currentItem;
60 }
61
62 void KItemListSelectionManager::setSelectedItems(const QSet<int>& items)
63 {
64 if (m_selectedItems != items) {
65 const QSet<int> previous = m_selectedItems;
66 m_selectedItems = items;
67 emit selectionChanged(m_selectedItems, previous);
68 }
69 }
70
71 QSet<int> KItemListSelectionManager::selectedItems() const
72 {
73 QSet<int> selectedItems = m_selectedItems;
74
75 if (m_isAnchoredSelectionActive) {
76 const int from = qMin(m_anchorItem, m_currentItem);
77 const int to = qMax(m_anchorItem, m_currentItem);
78
79 for (int index = from; index <= to; index++) {
80 switch (m_anchoredSelectionMode) {
81 case Select:
82 selectedItems.insert(index);
83 break;
84 case Deselect:
85 selectedItems.remove(index);
86 break;
87 case Toggle:
88 if (selectedItems.contains(index)) {
89 selectedItems.remove(index);
90 } else {
91 selectedItems.insert(index);
92 }
93 break;
94 }
95 }
96 }
97
98 return selectedItems;
99 }
100
101 bool KItemListSelectionManager::hasSelection() const
102 {
103 return !m_selectedItems.isEmpty() || (m_isAnchoredSelectionActive && m_anchoredSelectionMode == KItemListSelectionManager::Select);
104 }
105
106 void KItemListSelectionManager::setSelected(int index, int count, SelectionMode mode)
107 {
108 if (index < 0 || count < 1 || !m_model || index >= m_model->count()) {
109 return;
110 }
111
112 const QSet<int> previous = m_selectedItems;
113
114 count = qMin(count, m_model->count() - index);
115
116 const int endIndex = index + count -1;
117 switch (mode) {
118 case Select:
119 for (int i = index; i <= endIndex; ++i) {
120 m_selectedItems.insert(i);
121 }
122 break;
123
124 case Deselect:
125 for (int i = index; i <= endIndex; ++i) {
126 m_selectedItems.remove(i);
127 }
128 break;
129
130 case Toggle:
131 for (int i = index; i <= endIndex; ++i) {
132 if (m_selectedItems.contains(i)) {
133 m_selectedItems.remove(i);
134 } else {
135 m_selectedItems.insert(i);
136 }
137 }
138 break;
139
140 default:
141 Q_ASSERT(false);
142 break;
143 }
144
145 if (m_selectedItems != previous) {
146 emit selectionChanged(m_selectedItems, previous);
147 }
148 }
149
150 void KItemListSelectionManager::clearSelection()
151 {
152 if (!m_selectedItems.isEmpty()) {
153 const QSet<int> previous = m_selectedItems;
154 m_selectedItems.clear();
155 m_isAnchoredSelectionActive = false;
156 emit selectionChanged(m_selectedItems, previous);
157 }
158 else if (m_isAnchoredSelectionActive) {
159 m_isAnchoredSelectionActive = false;
160 // TODO: the 'previous' parameter of the signal has to be set correctly, but do we actually need it?
161 emit selectionChanged(m_selectedItems, m_selectedItems);
162 }
163 }
164
165 void KItemListSelectionManager::beginAnchoredSelection(int anchor, SelectionMode mode)
166 {
167 Q_UNUSED(anchor);
168 Q_UNUSED(mode);
169 }
170
171 void KItemListSelectionManager::endAnchoredSelection()
172 {
173 }
174
175 void KItemListSelectionManager::setAnchorItem(int anchor)
176 {
177 const int previous = m_anchorItem;
178 if (m_model && anchor < m_model->count()) {
179 m_anchorItem = anchor;
180 } else {
181 m_anchorItem = -1;
182 }
183
184 if (m_anchorItem != previous) {
185 emit anchorChanged(m_anchorItem, previous);
186 }
187 }
188
189 int KItemListSelectionManager::anchorItem() const
190 {
191 return m_anchorItem;
192 }
193
194 bool KItemListSelectionManager::isAnchoredSelectionActive() const
195 {
196 return m_isAnchoredSelectionActive;
197 }
198
199 void KItemListSelectionManager::setAnchoredSelectionActive(bool active)
200 {
201 m_isAnchoredSelectionActive = active;
202 }
203
204 KItemListSelectionManager::SelectionMode KItemListSelectionManager::anchoredSelectionMode() const
205 {
206 return m_anchoredSelectionMode;
207 }
208
209 void KItemListSelectionManager::setAnchoredSelectionMode(KItemListSelectionManager::SelectionMode mode)
210 {
211 m_anchoredSelectionMode = mode;
212 }
213
214 KItemModelBase* KItemListSelectionManager::model() const
215 {
216 return m_model;
217 }
218
219 void KItemListSelectionManager::setModel(KItemModelBase* model)
220 {
221 m_model = model;
222 if (model && model->count() > 0) {
223 m_currentItem = 0;
224 }
225 }
226
227 void KItemListSelectionManager::itemsInserted(const KItemRangeList& itemRanges)
228 {
229 // Update the current item
230 if (m_currentItem < 0) {
231 setCurrentItem(0);
232 } else {
233 int inc = 0;
234 foreach (const KItemRange& itemRange, itemRanges) {
235 if (m_currentItem < itemRange.index) {
236 break;
237 }
238 inc += itemRange.count;
239 }
240 setCurrentItem(m_currentItem + inc);
241 }
242
243 // Update the anchor item
244 if (m_anchorItem < 0) {
245 setAnchorItem(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 setAnchorItem(m_anchorItem + inc);
255 }
256
257 // Update the selections
258 if (!m_selectedItems.isEmpty()) {
259 const QSet<int> previous = m_selectedItems;
260
261 QSet<int> current;
262 current.reserve(m_selectedItems.count());
263 QSetIterator<int> it(m_selectedItems);
264 while (it.hasNext()) {
265 const int index = it.next();
266 int inc = 0;
267 foreach (const KItemRange& itemRange, itemRanges) {
268 if (index < itemRange.index) {
269 break;
270 }
271 inc += itemRange.count;
272 }
273 current.insert(index + inc);
274 }
275
276 if (current != previous) {
277 m_selectedItems = current;
278 emit selectionChanged(current, previous);
279 }
280 }
281 }
282
283 void KItemListSelectionManager::itemsRemoved(const KItemRangeList& itemRanges)
284 {
285 // Update the current item
286 if (m_currentItem >= 0) {
287 int currentItem = m_currentItem;
288 foreach (const KItemRange& itemRange, itemRanges) {
289 if (currentItem < itemRange.index) {
290 break;
291 }
292 if (currentItem >= itemRange.index + itemRange.count) {
293 currentItem -= itemRange.count;
294 } else if (currentItem >= m_model->count()) {
295 currentItem = m_model->count() - 1;
296 }
297 }
298 setCurrentItem(currentItem);
299 }
300
301 // Update the anchor item
302 if (m_anchorItem >= 0) {
303 int anchorItem = m_anchorItem;
304 foreach (const KItemRange& itemRange, itemRanges) {
305 if (anchorItem < itemRange.index) {
306 break;
307 }
308 if (anchorItem >= itemRange.index + itemRange.count) {
309 anchorItem -= itemRange.count;
310 } else if (anchorItem >= m_model->count()) {
311 anchorItem = m_model->count() - 1;
312 }
313 }
314 setAnchorItem(anchorItem);
315 }
316
317 // Update the selections
318 if (!m_selectedItems.isEmpty()) {
319 const QSet<int> previous = m_selectedItems;
320
321 QSet<int> current;
322 current.reserve(m_selectedItems.count());
323 QSetIterator<int> it(m_selectedItems);
324 while (it.hasNext()) {
325 int index = it.next();
326 int dec = 0;
327 foreach (const KItemRange& itemRange, itemRanges) {
328 if (index < itemRange.index) {
329 break;
330 }
331
332 if (index < itemRange.index + itemRange.count) {
333 // The selection is part of the removed range
334 // and will get deleted
335 index = -1;
336 break;
337 }
338
339 dec += itemRange.count;
340 }
341 index -= dec;
342 if (index >= 0) {
343 current.insert(index);
344 }
345 }
346
347 if (current != previous) {
348 m_selectedItems = current;
349 emit selectionChanged(current, previous);
350 }
351 }
352 }
353
354 #include "kitemlistselectionmanager.moc"