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