]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistcontroller.cpp
Added the functionality to activate items by pressing 'enter' or 'return' key on...
[dolphin.git] / src / kitemviews / kitemlistcontroller.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 "kitemlistcontroller.h"
24
25 #include "kitemlistview.h"
26 #include "kitemlistrubberband_p.h"
27 #include "kitemlistselectionmanager.h"
28 #include "kitemlistkeyboardsearchmanager_p.h"
29
30 #include <QApplication>
31 #include <QDrag>
32 #include <QEvent>
33 #include <QGraphicsSceneEvent>
34 #include <QMimeData>
35
36 #include <KGlobalSettings>
37 #include <KDebug>
38
39 KItemListController::KItemListController(QObject* parent) :
40 QObject(parent),
41 m_dragging(false),
42 m_selectionBehavior(NoSelection),
43 m_model(0),
44 m_view(0),
45 m_selectionManager(new KItemListSelectionManager(this)),
46 m_keyboardManager(new KItemListKeyboardSearchManager(this)),
47 m_pressedIndex(-1),
48 m_pressedMousePos(),
49 m_oldSelection()
50 {
51 connect(m_keyboardManager, SIGNAL(requestItemActivation(QString,bool)), this, SLOT(slotKeyboardActivationRequested(QString,bool)));
52 }
53
54 KItemListController::~KItemListController()
55 {
56 }
57
58 void KItemListController::setModel(KItemModelBase* model)
59 {
60 if (m_model == model) {
61 return;
62 }
63
64 KItemModelBase* oldModel = m_model;
65 m_model = model;
66
67 if (m_view) {
68 m_view->setModel(m_model);
69 }
70
71 m_selectionManager->setModel(m_model);
72
73 emit modelChanged(m_model, oldModel);
74 }
75
76 KItemModelBase* KItemListController::model() const
77 {
78 return m_model;
79 }
80
81 KItemListSelectionManager* KItemListController::selectionManager() const
82 {
83 return m_selectionManager;
84 }
85
86 void KItemListController::setView(KItemListView* view)
87 {
88 if (m_view == view) {
89 return;
90 }
91
92 KItemListView* oldView = m_view;
93 if (oldView) {
94 disconnect(oldView, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal)));
95 }
96
97 m_view = view;
98
99 if (m_view) {
100 m_view->setController(this);
101 m_view->setModel(m_model);
102 connect(m_view, SIGNAL(offsetChanged(qreal,qreal)), this, SLOT(slotViewOffsetChanged(qreal,qreal)));
103 }
104
105 emit viewChanged(m_view, oldView);
106 }
107
108 KItemListView* KItemListController::view() const
109 {
110 return m_view;
111 }
112
113 void KItemListController::setSelectionBehavior(SelectionBehavior behavior)
114 {
115 m_selectionBehavior = behavior;
116 }
117
118 KItemListController::SelectionBehavior KItemListController::selectionBehavior() const
119 {
120 return m_selectionBehavior;
121 }
122
123 bool KItemListController::showEvent(QShowEvent* event)
124 {
125 Q_UNUSED(event);
126 return false;
127 }
128
129 bool KItemListController::hideEvent(QHideEvent* event)
130 {
131 Q_UNUSED(event);
132 return false;
133 }
134
135 bool KItemListController::keyPressEvent(QKeyEvent* event)
136 {
137 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
138 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
139 const bool shiftOrControlPressed = shiftPressed || controlPressed;
140
141 int index = m_selectionManager->currentItem();
142 const int itemCount = m_model->count();
143 const int itemsPerRow = m_view->itemsPerOffset();
144
145 // For horizontal scroll orientation, transform
146 // the arrow keys to simplify the event handling.
147 int key = event->key();
148 if (m_view->scrollOrientation() == Qt::Horizontal) {
149 switch (key) {
150 case Qt::Key_Up: key = Qt::Key_Left; break;
151 case Qt::Key_Down: key = Qt::Key_Right; break;
152 case Qt::Key_Left: key = Qt::Key_Up; break;
153 case Qt::Key_Right: key = Qt::Key_Down; break;
154 default: break;
155 }
156 }
157
158 switch (key) {
159 case Qt::Key_Home:
160 index = 0;
161 break;
162
163 case Qt::Key_End:
164 index = itemCount - 1;
165 break;
166
167 case Qt::Key_Left:
168 if (index > 0) {
169 index--;
170 }
171 break;
172
173 case Qt::Key_Right:
174 if (index < itemCount - 1) {
175 index++;
176 }
177 break;
178
179 case Qt::Key_Up:
180 if (index >= itemsPerRow) {
181 index -= itemsPerRow;
182 }
183 break;
184
185 case Qt::Key_Down:
186 if (index + itemsPerRow < itemCount) {
187 // We are not in the last row yet.
188 index += itemsPerRow;
189 }
190 else {
191 // We are either in the last row already, or we are in the second-last row,
192 // and there is no item below the current item.
193 // In the latter case, we jump to the very last item.
194 const int currentColumn = index % itemsPerRow;
195 const int lastItemColumn = (itemCount - 1) % itemsPerRow;
196 const bool inLastRow = currentColumn < lastItemColumn;
197 if (!inLastRow) {
198 index = itemCount - 1;
199 }
200 }
201 break;
202
203 case Qt::Key_Enter:
204 case Qt::Key_Return:
205 emit itemActivated(index);
206 break;
207
208 case Qt::Key_Space:
209 if (controlPressed) {
210 m_selectionManager->endAnchoredSelection();
211 m_selectionManager->setSelected(index, 1, KItemListSelectionManager::Toggle);
212 m_selectionManager->beginAnchoredSelection(index);
213 break;
214 }
215
216 default:
217 m_keyboardManager->addKeys(event->text());
218 return false;
219 }
220
221 if (m_selectionManager->currentItem() != index) {
222 if (controlPressed) {
223 m_selectionManager->endAnchoredSelection();
224 }
225
226 m_selectionManager->setCurrentItem(index);
227
228 if (!shiftOrControlPressed || m_selectionBehavior == SingleSelection) {
229 m_selectionManager->clearSelection();
230 m_selectionManager->setSelected(index, 1);
231 }
232
233 if (!shiftPressed) {
234 m_selectionManager->beginAnchoredSelection(index);
235 }
236 }
237 return true;
238 }
239
240 void KItemListController::slotKeyboardActivationRequested(const QString& text, bool searchFromNextItem)
241 {
242 if (!m_model) {
243 return;
244 }
245 const int currentIndex = m_selectionManager->currentItem();
246 int index;
247 if (searchFromNextItem) {
248 index = m_model->indexForKeyboardSearch(text, (currentIndex + 1) % m_model->count());
249 }
250 else {
251 index = m_model->indexForKeyboardSearch(text, currentIndex);
252 }
253 if (index >= 0) {
254 m_selectionManager->setCurrentItem(index);
255 m_selectionManager->clearSelection();
256 m_selectionManager->setSelected(index, 1);
257 m_selectionManager->beginAnchoredSelection(index);
258 }
259 }
260
261 bool KItemListController::inputMethodEvent(QInputMethodEvent* event)
262 {
263 Q_UNUSED(event);
264 return false;
265 }
266
267 bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
268 {
269 if (!m_view) {
270 return false;
271 }
272
273 m_dragging = false;
274 m_pressedMousePos = transform.map(event->pos());
275 m_pressedIndex = m_view->itemAt(m_pressedMousePos);
276
277 if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) {
278 m_selectionManager->setCurrentItem(m_pressedIndex);
279 return true;
280 }
281
282 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
283 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
284
285 if (m_selectionBehavior == SingleSelection) {
286 m_selectionManager->clearSelection();
287 }
288
289 if (!shiftPressed) {
290 // Finish the anchored selection before the current index is changed
291 m_selectionManager->endAnchoredSelection();
292 }
293
294 if (m_pressedIndex >= 0) {
295 m_selectionManager->setCurrentItem(m_pressedIndex);
296
297 switch (m_selectionBehavior) {
298 case NoSelection:
299 break;
300
301 case SingleSelection:
302 m_selectionManager->setSelected(m_pressedIndex);
303 break;
304
305 case MultiSelection:
306 if (controlPressed) {
307 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
308 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
309 } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
310 // Select the pressed item and start a new anchored selection
311 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select);
312 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
313 }
314 break;
315
316 default:
317 Q_ASSERT(false);
318 break;
319 }
320
321 return true;
322 } else {
323 KItemListRubberBand* rubberBand = m_view->rubberBand();
324 QPointF startPos = m_pressedMousePos;
325 if (m_view->scrollOrientation() == Qt::Vertical) {
326 startPos.ry() += m_view->offset();
327 if (m_view->itemSize().width() < 0) {
328 // Use a special rubberband for views that have only one column and
329 // expand the rubberband to use the whole width of the view.
330 startPos.setX(0);
331 }
332 } else {
333 startPos.rx() += m_view->offset();
334 }
335
336 m_oldSelection = m_selectionManager->selectedItems();
337 rubberBand->setStartPosition(startPos);
338 rubberBand->setEndPosition(startPos);
339 rubberBand->setActive(true);
340 connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
341 m_view->setAutoScroll(true);
342 }
343
344 return false;
345 }
346
347 bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
348 {
349 if (!m_view) {
350 return false;
351 }
352
353 if (m_pressedIndex >= 0) {
354 // Check whether a dragging should be started
355 if (!m_dragging && (event->buttons() & Qt::LeftButton)) {
356 const QPointF pos = transform.map(event->pos());
357 const qreal minDragDiff = 4;
358 const bool hasMinDragDiff = qAbs(pos.x() - m_pressedMousePos.x()) >= minDragDiff ||
359 qAbs(pos.y() - m_pressedMousePos.y()) >= minDragDiff;
360 if (hasMinDragDiff && startDragging()) {
361 m_dragging = true;
362 }
363 }
364 } else {
365 KItemListRubberBand* rubberBand = m_view->rubberBand();
366 if (rubberBand->isActive()) {
367 QPointF endPos = transform.map(event->pos());
368 if (m_view->scrollOrientation() == Qt::Vertical) {
369 endPos.ry() += m_view->offset();
370 if (m_view->itemSize().width() < 0) {
371 // Use a special rubberband for views that have only one column and
372 // expand the rubberband to use the whole width of the view.
373 endPos.setX(m_view->size().width());
374 }
375 } else {
376 endPos.rx() += m_view->offset();
377 }
378 rubberBand->setEndPosition(endPos);
379 }
380 }
381
382 return false;
383 }
384
385 bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
386 {
387 if (!m_view) {
388 return false;
389 }
390
391 const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier ||
392 event->modifiers() & Qt::ControlModifier;
393
394 bool clearSelection = !shiftOrControlPressed && !m_dragging && !(event->button() == Qt::RightButton);
395
396 KItemListRubberBand* rubberBand = m_view->rubberBand();
397 if (rubberBand->isActive()) {
398 disconnect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
399 rubberBand->setActive(false);
400 m_oldSelection.clear();
401 m_view->setAutoScroll(false);
402
403 if (rubberBand->startPosition() != rubberBand->endPosition()) {
404 clearSelection = false;
405 }
406 }
407
408 const QPointF pos = transform.map(event->pos());
409 const int index = m_view->itemAt(pos);
410
411 if (index >= 0 && index == m_pressedIndex) {
412 // The release event is done above the same item as the press event
413
414 if (clearSelection) {
415 // Clear the previous selection but reselect the current index
416 m_selectionManager->setSelectedItems(QSet<int>() << index);
417 }
418
419 if (event->button() & Qt::LeftButton) {
420 bool emitItemActivated = true;
421 if (m_view->isAboveExpansionToggle(index, pos)) {
422 emit itemExpansionToggleClicked(index);
423 emitItemActivated = false;
424 } else if (shiftOrControlPressed) {
425 // The mouse click should only update the selection, not trigger the item
426 emitItemActivated = false;
427 } else if (!KGlobalSettings::singleClick()) {
428 emitItemActivated = false;
429 }
430 if (emitItemActivated) {
431 emit itemActivated(index);
432 }
433 } else if (event->button() & Qt::MidButton) {
434 emit itemMiddleClicked(index);
435 } else if (event->button() & Qt::RightButton) {
436 emit contextMenuRequested(index, QPointF(event->pos()));
437 }
438 } else if (clearSelection) {
439 m_selectionManager->clearSelection();
440 }
441
442 m_dragging = false;
443 m_pressedMousePos = QPointF();
444 m_pressedIndex = -1;
445 return false;
446 }
447
448 bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
449 {
450 const QPointF pos = transform.map(event->pos());
451 const int index = m_view->itemAt(pos);
452
453 bool emitItemActivated = !KGlobalSettings::singleClick() &&
454 (event->button() & Qt::LeftButton) &&
455 index >= 0 && index < m_model->count();
456 if (emitItemActivated) {
457 emit itemActivated(index);
458 }
459 return false;
460 }
461
462 bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
463 {
464 Q_UNUSED(event);
465 Q_UNUSED(transform);
466 return false;
467 }
468
469 bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
470 {
471 Q_UNUSED(event);
472 Q_UNUSED(transform);
473 return false;
474 }
475
476 bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
477 {
478 Q_UNUSED(event);
479 Q_UNUSED(transform);
480 return false;
481 }
482
483 bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
484 {
485 Q_UNUSED(event);
486 Q_UNUSED(transform);
487
488 m_dragging = false;
489 return false;
490 }
491
492 bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
493 {
494 Q_UNUSED(event);
495 Q_UNUSED(transform);
496 return false;
497 }
498
499 bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
500 {
501 // The implementation assumes that only one item can get hovered no matter
502 // whether they overlap or not.
503
504 Q_UNUSED(transform);
505 if (!m_model || !m_view) {
506 return false;
507 }
508
509 // Search the previously hovered item that might get unhovered
510 KItemListWidget* unhoveredWidget = 0;
511 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
512 if (widget->isHovered()) {
513 unhoveredWidget = widget;
514 break;
515 }
516 }
517
518 // Search the currently hovered item
519 KItemListWidget* hoveredWidget = 0;
520 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
521 const QPointF mappedPos = widget->mapFromItem(m_view, event->pos());
522
523 const bool hovered = widget->contains(mappedPos) &&
524 !widget->expansionToggleRect().contains(mappedPos) &&
525 !widget->selectionToggleRect().contains(mappedPos);
526 if (hovered) {
527 hoveredWidget = widget;
528 break;
529 }
530 }
531
532 if (unhoveredWidget != hoveredWidget) {
533 if (unhoveredWidget) {
534 unhoveredWidget->setHovered(false);
535 emit itemUnhovered(unhoveredWidget->index());
536 }
537
538 if (hoveredWidget) {
539 hoveredWidget->setHovered(true);
540 emit itemHovered(hoveredWidget->index());
541 }
542 }
543
544 return false;
545 }
546
547 bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
548 {
549 Q_UNUSED(event);
550 Q_UNUSED(transform);
551
552 if (!m_model || !m_view) {
553 return false;
554 }
555
556 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
557 if (widget->isHovered()) {
558 widget->setHovered(false);
559 emit itemUnhovered(widget->index());
560 }
561 }
562 return false;
563 }
564
565 bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
566 {
567 Q_UNUSED(event);
568 Q_UNUSED(transform);
569 return false;
570 }
571
572 bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
573 {
574 Q_UNUSED(event);
575 Q_UNUSED(transform);
576 return false;
577 }
578
579 bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
580 {
581 if (!event) {
582 return false;
583 }
584
585 switch (event->type()) {
586 case QEvent::KeyPress:
587 return keyPressEvent(static_cast<QKeyEvent*>(event));
588 case QEvent::InputMethod:
589 return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
590 case QEvent::GraphicsSceneMousePress:
591 return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
592 case QEvent::GraphicsSceneMouseMove:
593 return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
594 case QEvent::GraphicsSceneMouseRelease:
595 return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
596 case QEvent::GraphicsSceneMouseDoubleClick:
597 return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
598 case QEvent::GraphicsSceneWheel:
599 return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
600 case QEvent::GraphicsSceneDragEnter:
601 return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
602 case QEvent::GraphicsSceneDragLeave:
603 return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
604 case QEvent::GraphicsSceneDragMove:
605 return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
606 case QEvent::GraphicsSceneDrop:
607 return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
608 case QEvent::GraphicsSceneHoverEnter:
609 return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
610 case QEvent::GraphicsSceneHoverMove:
611 return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
612 case QEvent::GraphicsSceneHoverLeave:
613 return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
614 case QEvent::GraphicsSceneResize:
615 return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
616 default:
617 break;
618 }
619
620 return false;
621 }
622
623 void KItemListController::slotViewOffsetChanged(qreal current, qreal previous)
624 {
625 if (!m_view) {
626 return;
627 }
628
629 KItemListRubberBand* rubberBand = m_view->rubberBand();
630 if (rubberBand->isActive()) {
631 const qreal diff = current - previous;
632 // TODO: Ideally just QCursor::pos() should be used as
633 // new end-position but it seems there is no easy way
634 // to have something like QWidget::mapFromGlobal() for QGraphicsWidget
635 // (... or I just missed an easy way to do the mapping)
636 QPointF endPos = rubberBand->endPosition();
637 if (m_view->scrollOrientation() == Qt::Vertical) {
638 endPos.ry() += diff;
639 } else {
640 endPos.rx() += diff;
641 }
642
643 rubberBand->setEndPosition(endPos);
644 }
645 }
646
647 void KItemListController::slotRubberBandChanged()
648 {
649 if (!m_view || !m_model || m_model->count() <= 0) {
650 return;
651 }
652
653 const KItemListRubberBand* rubberBand = m_view->rubberBand();
654 const QPointF startPos = rubberBand->startPosition();
655 const QPointF endPos = rubberBand->endPosition();
656 QRectF rubberBandRect = QRectF(startPos, endPos).normalized();
657
658 const bool scrollVertical = (m_view->scrollOrientation() == Qt::Vertical);
659 if (scrollVertical) {
660 rubberBandRect.translate(0, -m_view->offset());
661 } else {
662 rubberBandRect.translate(-m_view->offset(), 0);
663 }
664
665 if (!m_oldSelection.isEmpty()) {
666 // Clear the old selection that was available before the rubberband has
667 // been activated in case if no Shift- or Control-key are pressed
668 const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier ||
669 QApplication::keyboardModifiers() & Qt::ControlModifier;
670 if (!shiftOrControlPressed) {
671 m_oldSelection.clear();
672 }
673 }
674
675 QSet<int> selectedItems;
676
677 // Select all visible items that intersect with the rubberband
678 foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) {
679 const int index = widget->index();
680
681 const QRectF widgetRect = m_view->itemBoundingRect(index);
682 if (widgetRect.intersects(rubberBandRect)) {
683 const QRectF iconRect = widget->iconBoundingRect().translated(widgetRect.topLeft());
684 const QRectF textRect = widget->textBoundingRect().translated(widgetRect.topLeft());
685 if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) {
686 selectedItems.insert(index);
687 }
688 }
689 }
690
691 // Select all invisible items that intersect with the rubberband. Instead of
692 // iterating all items only the area which might be touched by the rubberband
693 // will be checked.
694 const bool increaseIndex = scrollVertical ?
695 startPos.y() > endPos.y(): startPos.x() > endPos.x();
696
697 int index = increaseIndex ? m_view->lastVisibleIndex() + 1 : m_view->firstVisibleIndex() - 1;
698 bool selectionFinished = false;
699 do {
700 const QRectF widgetRect = m_view->itemBoundingRect(index);
701 if (widgetRect.intersects(rubberBandRect)) {
702 selectedItems.insert(index);
703 }
704
705 if (increaseIndex) {
706 ++index;
707 selectionFinished = (index >= m_model->count()) ||
708 ( scrollVertical && widgetRect.top() > rubberBandRect.bottom()) ||
709 (!scrollVertical && widgetRect.left() > rubberBandRect.right());
710 } else {
711 --index;
712 selectionFinished = (index < 0) ||
713 ( scrollVertical && widgetRect.bottom() < rubberBandRect.top()) ||
714 (!scrollVertical && widgetRect.right() < rubberBandRect.left());
715 }
716 } while (!selectionFinished);
717
718 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
719 // If Control is pressed, the selection state of all items in the rubberband is toggled.
720 // Therefore, the new selection contains:
721 // 1. All previously selected items which are not inside the rubberband, and
722 // 2. all items inside the rubberband which have not been selected previously.
723 m_selectionManager->setSelectedItems((m_oldSelection - selectedItems) + (selectedItems - m_oldSelection));
724 }
725 else {
726 m_selectionManager->setSelectedItems(selectedItems + m_oldSelection);
727 }
728 }
729
730 bool KItemListController::startDragging()
731 {
732 if (!m_view || !m_model) {
733 return false;
734 }
735
736 const QSet<int> selectedItems = m_selectionManager->selectedItems();
737 QMimeData* data = m_model->createMimeData(selectedItems);
738 if (!data) {
739 return false;
740 }
741
742 // The created drag object will be owned and deleted
743 // by QApplication::activeWindow().
744 QDrag* drag = new QDrag(QApplication::activeWindow());
745 drag->setMimeData(data);
746
747 const QPixmap pixmap = m_view->createDragPixmap(selectedItems);
748 drag->setPixmap(pixmap);
749
750 drag->exec(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction, Qt::IgnoreAction);
751 return true;
752 }
753
754 #include "kitemlistcontroller.moc"