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