]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistcontroller.cpp
4a81eaaa59037244e1f29c05e08957d70fdba235
[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_selectionBehavior(NoSelection),
42 m_model(0),
43 m_view(0),
44 m_selectionManager(new KItemListSelectionManager(this)),
45 m_keyboardManager(new KItemListKeyboardSearchManager(this)),
46 m_pressedIndex(-1),
47 m_pressedMousePos(),
48 m_oldSelection()
49 {
50 connect(m_keyboardManager, SIGNAL(changeCurrentItem(QString,bool)),
51 this, SLOT(slotChangeCurrentItem(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::slotChangeCurrentItem(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_pressedMousePos = transform.map(event->pos());
274 m_pressedIndex = m_view->itemAt(m_pressedMousePos);
275
276 if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) {
277 m_selectionManager->setCurrentItem(m_pressedIndex);
278 return true;
279 }
280
281 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
282 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
283
284 if (m_selectionBehavior == SingleSelection) {
285 m_selectionManager->clearSelection();
286 }
287
288 if (!shiftPressed) {
289 // Finish the anchored selection before the current index is changed
290 m_selectionManager->endAnchoredSelection();
291 }
292
293 if (m_pressedIndex >= 0) {
294 m_selectionManager->setCurrentItem(m_pressedIndex);
295
296 switch (m_selectionBehavior) {
297 case NoSelection:
298 break;
299
300 case SingleSelection:
301 m_selectionManager->setSelected(m_pressedIndex);
302 break;
303
304 case MultiSelection:
305 if (controlPressed) {
306 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
307 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
308 } else if (event->buttons() & Qt::RightButton) {
309 // Only clear the selection if a context menu is requested above a non-selected item
310 if (!m_selectionManager->selectedItems().contains(m_pressedIndex)) {
311 m_selectionManager->setSelectedItems(QSet<int>() << m_pressedIndex);
312 }
313 } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
314 // Select the pressed item and start a new anchored selection
315 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select);
316 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
317 }
318 break;
319
320 default:
321 Q_ASSERT(false);
322 break;
323 }
324
325 return true;
326 } else {
327 if (event->buttons() & Qt::RightButton) {
328 m_selectionManager->clearSelection();
329 }
330
331 KItemListRubberBand* rubberBand = m_view->rubberBand();
332 QPointF startPos = m_pressedMousePos;
333 if (m_view->scrollOrientation() == Qt::Vertical) {
334 startPos.ry() += m_view->offset();
335 if (m_view->itemSize().width() < 0) {
336 // Use a special rubberband for views that have only one column and
337 // expand the rubberband to use the whole width of the view.
338 startPos.setX(0);
339 }
340 } else {
341 startPos.rx() += m_view->offset();
342 }
343
344 m_oldSelection = m_selectionManager->selectedItems();
345 rubberBand->setStartPosition(startPos);
346 rubberBand->setEndPosition(startPos);
347 rubberBand->setActive(true);
348 connect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
349 m_view->setAutoScroll(true);
350 }
351
352 return false;
353 }
354
355 bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
356 {
357 if (!m_view) {
358 return false;
359 }
360
361 if (m_pressedIndex >= 0) {
362 // Check whether a dragging should be started
363 if (event->buttons() & Qt::LeftButton) {
364 const QPointF pos = transform.map(event->pos());
365 if ((pos - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) {
366 startDragging();
367 }
368 }
369 } else {
370 KItemListRubberBand* rubberBand = m_view->rubberBand();
371 if (rubberBand->isActive()) {
372 QPointF endPos = transform.map(event->pos());
373 if (m_view->scrollOrientation() == Qt::Vertical) {
374 endPos.ry() += m_view->offset();
375 if (m_view->itemSize().width() < 0) {
376 // Use a special rubberband for views that have only one column and
377 // expand the rubberband to use the whole width of the view.
378 endPos.setX(m_view->size().width());
379 }
380 } else {
381 endPos.rx() += m_view->offset();
382 }
383 rubberBand->setEndPosition(endPos);
384 }
385 }
386
387 return false;
388 }
389
390 bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
391 {
392 if (!m_view) {
393 return false;
394 }
395
396 const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier ||
397 event->modifiers() & Qt::ControlModifier;
398
399 bool clearSelection = !shiftOrControlPressed && event->button() != Qt::RightButton;
400
401 KItemListRubberBand* rubberBand = m_view->rubberBand();
402 if (rubberBand->isActive()) {
403 disconnect(rubberBand, SIGNAL(endPositionChanged(QPointF,QPointF)), this, SLOT(slotRubberBandChanged()));
404 rubberBand->setActive(false);
405 m_oldSelection.clear();
406 m_view->setAutoScroll(false);
407
408 if (rubberBand->startPosition() != rubberBand->endPosition()) {
409 clearSelection = false;
410 }
411 }
412
413 const QPointF pos = transform.map(event->pos());
414 const int index = m_view->itemAt(pos);
415
416 if (index >= 0 && index == m_pressedIndex) {
417 // The release event is done above the same item as the press event
418
419 if (clearSelection) {
420 // Clear the previous selection but reselect the current index
421 m_selectionManager->setSelectedItems(QSet<int>() << index);
422 }
423
424 if (event->button() & Qt::LeftButton) {
425 bool emitItemActivated = true;
426 if (m_view->isAboveExpansionToggle(index, pos)) {
427 emit itemExpansionToggleClicked(index);
428 emitItemActivated = false;
429 } else if (shiftOrControlPressed) {
430 // The mouse click should only update the selection, not trigger the item
431 emitItemActivated = false;
432 } else if (!KGlobalSettings::singleClick()) {
433 emitItemActivated = false;
434 }
435 if (emitItemActivated) {
436 emit itemActivated(index);
437 }
438 } else if (event->button() & Qt::MidButton) {
439 emit itemMiddleClicked(index);
440 } else if (event->button() & Qt::RightButton) {
441 emit contextMenuRequested(index, QPointF(event->pos()));
442 }
443 } else if (clearSelection) {
444 m_selectionManager->clearSelection();
445 }
446
447 m_pressedMousePos = QPointF();
448 m_pressedIndex = -1;
449 return false;
450 }
451
452 bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
453 {
454 const QPointF pos = transform.map(event->pos());
455 const int index = m_view->itemAt(pos);
456
457 bool emitItemActivated = !KGlobalSettings::singleClick() &&
458 (event->button() & Qt::LeftButton) &&
459 index >= 0 && index < m_model->count();
460 if (emitItemActivated) {
461 emit itemActivated(index);
462 }
463 return false;
464 }
465
466 bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
467 {
468 Q_UNUSED(event);
469 Q_UNUSED(transform);
470 return false;
471 }
472
473 bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
474 {
475 Q_UNUSED(event);
476 Q_UNUSED(transform);
477 return false;
478 }
479
480 bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
481 {
482 Q_UNUSED(transform);
483 if (!m_model || !m_view) {
484 return false;
485 }
486
487 KItemListWidget* oldHoveredWidget = hoveredWidget();
488 KItemListWidget* newHoveredWidget = widgetForPos(event->pos());
489 if (oldHoveredWidget != newHoveredWidget) {
490 if (oldHoveredWidget) {
491 oldHoveredWidget->setHovered(false);
492 emit itemUnhovered(oldHoveredWidget->index());
493 }
494
495 if (newHoveredWidget) {
496 const int index = newHoveredWidget->index();
497 if (m_model->supportsDropping(index)) {
498 newHoveredWidget->setHovered(true);
499 }
500 emit itemHovered(index);
501 }
502 }
503
504 return false;
505 }
506
507 bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
508 {
509 Q_UNUSED(transform)
510 if (!m_view) {
511 return false;
512 }
513
514 const QPointF pos = transform.map(event->pos());
515 const int index = m_view->itemAt(pos);
516 emit itemDropEvent(index, event);
517
518 return true;
519 }
520
521 bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
522 {
523 Q_UNUSED(event);
524 Q_UNUSED(transform);
525 return false;
526 }
527
528 bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
529 {
530 Q_UNUSED(transform);
531 if (!m_model || !m_view) {
532 return false;
533 }
534
535 KItemListWidget* oldHoveredWidget = hoveredWidget();
536 KItemListWidget* newHoveredWidget = widgetForPos(event->pos());
537 if (oldHoveredWidget != newHoveredWidget) {
538 if (oldHoveredWidget) {
539 oldHoveredWidget->setHovered(false);
540 emit itemUnhovered(oldHoveredWidget->index());
541 }
542
543 if (newHoveredWidget) {
544 newHoveredWidget->setHovered(true);
545 emit itemHovered(newHoveredWidget->index());
546 }
547 }
548
549 return false;
550 }
551
552 bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
553 {
554 Q_UNUSED(event);
555 Q_UNUSED(transform);
556
557 if (!m_model || !m_view) {
558 return false;
559 }
560
561 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
562 if (widget->isHovered()) {
563 widget->setHovered(false);
564 emit itemUnhovered(widget->index());
565 }
566 }
567 return false;
568 }
569
570 bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
571 {
572 Q_UNUSED(event);
573 Q_UNUSED(transform);
574 return false;
575 }
576
577 bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
578 {
579 Q_UNUSED(event);
580 Q_UNUSED(transform);
581 return false;
582 }
583
584 bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
585 {
586 if (!event) {
587 return false;
588 }
589
590 switch (event->type()) {
591 case QEvent::KeyPress:
592 return keyPressEvent(static_cast<QKeyEvent*>(event));
593 case QEvent::InputMethod:
594 return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
595 case QEvent::GraphicsSceneMousePress:
596 return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
597 case QEvent::GraphicsSceneMouseMove:
598 return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
599 case QEvent::GraphicsSceneMouseRelease:
600 return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
601 case QEvent::GraphicsSceneMouseDoubleClick:
602 return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
603 case QEvent::GraphicsSceneWheel:
604 return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
605 case QEvent::GraphicsSceneDragEnter:
606 return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
607 case QEvent::GraphicsSceneDragLeave:
608 return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
609 case QEvent::GraphicsSceneDragMove:
610 return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
611 case QEvent::GraphicsSceneDrop:
612 return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
613 case QEvent::GraphicsSceneHoverEnter:
614 return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
615 case QEvent::GraphicsSceneHoverMove:
616 return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
617 case QEvent::GraphicsSceneHoverLeave:
618 return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
619 case QEvent::GraphicsSceneResize:
620 return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
621 default:
622 break;
623 }
624
625 return false;
626 }
627
628 void KItemListController::slotViewOffsetChanged(qreal current, qreal previous)
629 {
630 if (!m_view) {
631 return;
632 }
633
634 KItemListRubberBand* rubberBand = m_view->rubberBand();
635 if (rubberBand->isActive()) {
636 const qreal diff = current - previous;
637 // TODO: Ideally just QCursor::pos() should be used as
638 // new end-position but it seems there is no easy way
639 // to have something like QWidget::mapFromGlobal() for QGraphicsWidget
640 // (... or I just missed an easy way to do the mapping)
641 QPointF endPos = rubberBand->endPosition();
642 if (m_view->scrollOrientation() == Qt::Vertical) {
643 endPos.ry() += diff;
644 } else {
645 endPos.rx() += diff;
646 }
647
648 rubberBand->setEndPosition(endPos);
649 }
650 }
651
652 void KItemListController::slotRubberBandChanged()
653 {
654 if (!m_view || !m_model || m_model->count() <= 0) {
655 return;
656 }
657
658 const KItemListRubberBand* rubberBand = m_view->rubberBand();
659 const QPointF startPos = rubberBand->startPosition();
660 const QPointF endPos = rubberBand->endPosition();
661 QRectF rubberBandRect = QRectF(startPos, endPos).normalized();
662
663 const bool scrollVertical = (m_view->scrollOrientation() == Qt::Vertical);
664 if (scrollVertical) {
665 rubberBandRect.translate(0, -m_view->offset());
666 } else {
667 rubberBandRect.translate(-m_view->offset(), 0);
668 }
669
670 if (!m_oldSelection.isEmpty()) {
671 // Clear the old selection that was available before the rubberband has
672 // been activated in case if no Shift- or Control-key are pressed
673 const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier ||
674 QApplication::keyboardModifiers() & Qt::ControlModifier;
675 if (!shiftOrControlPressed) {
676 m_oldSelection.clear();
677 }
678 }
679
680 QSet<int> selectedItems;
681
682 // Select all visible items that intersect with the rubberband
683 foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) {
684 const int index = widget->index();
685
686 const QRectF widgetRect = m_view->itemBoundingRect(index);
687 if (widgetRect.intersects(rubberBandRect)) {
688 const QRectF iconRect = widget->iconBoundingRect().translated(widgetRect.topLeft());
689 const QRectF textRect = widget->textBoundingRect().translated(widgetRect.topLeft());
690 if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) {
691 selectedItems.insert(index);
692 }
693 }
694 }
695
696 // Select all invisible items that intersect with the rubberband. Instead of
697 // iterating all items only the area which might be touched by the rubberband
698 // will be checked.
699 const bool increaseIndex = scrollVertical ?
700 startPos.y() > endPos.y(): startPos.x() > endPos.x();
701
702 int index = increaseIndex ? m_view->lastVisibleIndex() + 1 : m_view->firstVisibleIndex() - 1;
703 bool selectionFinished = false;
704 do {
705 const QRectF widgetRect = m_view->itemBoundingRect(index);
706 if (widgetRect.intersects(rubberBandRect)) {
707 selectedItems.insert(index);
708 }
709
710 if (increaseIndex) {
711 ++index;
712 selectionFinished = (index >= m_model->count()) ||
713 ( scrollVertical && widgetRect.top() > rubberBandRect.bottom()) ||
714 (!scrollVertical && widgetRect.left() > rubberBandRect.right());
715 } else {
716 --index;
717 selectionFinished = (index < 0) ||
718 ( scrollVertical && widgetRect.bottom() < rubberBandRect.top()) ||
719 (!scrollVertical && widgetRect.right() < rubberBandRect.left());
720 }
721 } while (!selectionFinished);
722
723 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
724 // If Control is pressed, the selection state of all items in the rubberband is toggled.
725 // Therefore, the new selection contains:
726 // 1. All previously selected items which are not inside the rubberband, and
727 // 2. all items inside the rubberband which have not been selected previously.
728 m_selectionManager->setSelectedItems((m_oldSelection - selectedItems) + (selectedItems - m_oldSelection));
729 }
730 else {
731 m_selectionManager->setSelectedItems(selectedItems + m_oldSelection);
732 }
733 }
734
735 void KItemListController::startDragging()
736 {
737 if (!m_view || !m_model) {
738 return;
739 }
740
741 const QSet<int> selectedItems = m_selectionManager->selectedItems();
742 QMimeData* data = m_model->createMimeData(selectedItems);
743 if (!data) {
744 return;
745 }
746
747 // The created drag object will be owned and deleted
748 // by QApplication::activeWindow().
749 QDrag* drag = new QDrag(QApplication::activeWindow());
750 drag->setMimeData(data);
751
752 const QPixmap pixmap = m_view->createDragPixmap(selectedItems);
753 drag->setPixmap(pixmap);
754
755 drag->exec(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction, Qt::IgnoreAction);
756 }
757
758 KItemListWidget* KItemListController::hoveredWidget() const
759 {
760 Q_ASSERT(m_view);
761
762 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
763 if (widget->isHovered()) {
764 return widget;
765 }
766 }
767
768 return 0;
769 }
770
771 KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
772 {
773 Q_ASSERT(m_view);
774
775 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
776 const QPointF mappedPos = widget->mapFromItem(m_view, pos);
777
778 const bool hovered = widget->contains(mappedPos) &&
779 !widget->expansionToggleRect().contains(mappedPos) &&
780 !widget->selectionToggleRect().contains(mappedPos);
781 if (hovered) {
782 return widget;
783 }
784 }
785
786 return 0;
787 }
788
789 #include "kitemlistcontroller.moc"