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