]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistcontroller.cpp
008b6c4c6cdb21a3a463a1d65709b37cb7214f2a
[dolphin.git] / src / kitemviews / kitemlistcontroller.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * Copyright (C) 2012 by Frank Reininghaus <frank78ac@googlemail.com> *
4 * *
5 * Based on the Itemviews NG project from Trolltech Labs: *
6 * http://qt.gitorious.org/qt-labs/itemviews-ng *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
22 ***************************************************************************/
23
24 #include "kitemlistcontroller.h"
25
26
27 #include "kitemlistview.h"
28 #include "kitemlistselectionmanager.h"
29
30 #include "private/kitemlistrubberband.h"
31 #include "private/kitemlistkeyboardsearchmanager.h"
32
33 #include <QApplication>
34 #include <QDrag>
35 #include <QEvent>
36 #include <QGraphicsScene>
37 #include <QGraphicsSceneEvent>
38 #include <QGraphicsView>
39 #include <QMimeData>
40 #include <QTimer>
41 #include <QAccessible>
42 #include <views/draganddrophelper.h>
43
44 KItemListController::KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent) :
45 QObject(parent),
46 m_singleClickActivationEnforced(false),
47 m_selectionTogglePressed(false),
48 m_clearSelectionIfItemsAreNotDragged(false),
49 m_selectionBehavior(NoSelection),
50 m_autoActivationBehavior(ActivationAndExpansion),
51 m_mouseDoubleClickAction(ActivateItemOnly),
52 m_model(0),
53 m_view(0),
54 m_selectionManager(new KItemListSelectionManager(this)),
55 m_keyboardManager(new KItemListKeyboardSearchManager(this)),
56 m_pressedIndex(-1),
57 m_pressedMousePos(),
58 m_autoActivationTimer(0),
59 m_oldSelection(),
60 m_keyboardAnchorIndex(-1),
61 m_keyboardAnchorPos(0)
62 {
63 connect(m_keyboardManager, &KItemListKeyboardSearchManager::changeCurrentItem,
64 this, &KItemListController::slotChangeCurrentItem);
65 connect(m_selectionManager, &KItemListSelectionManager::currentChanged,
66 m_keyboardManager, &KItemListKeyboardSearchManager::slotCurrentChanged);
67
68 m_autoActivationTimer = new QTimer(this);
69 m_autoActivationTimer->setSingleShot(true);
70 m_autoActivationTimer->setInterval(-1);
71 connect(m_autoActivationTimer, &QTimer::timeout, this, &KItemListController::slotAutoActivationTimeout);
72
73 setModel(model);
74 setView(view);
75 }
76
77 KItemListController::~KItemListController()
78 {
79 setView(0);
80 Q_ASSERT(!m_view);
81
82 setModel(0);
83 Q_ASSERT(!m_model);
84 }
85
86 void KItemListController::setModel(KItemModelBase* model)
87 {
88 if (m_model == model) {
89 return;
90 }
91
92 KItemModelBase* oldModel = m_model;
93 if (oldModel) {
94 oldModel->deleteLater();
95 }
96
97 m_model = model;
98 if (m_model) {
99 m_model->setParent(this);
100 }
101
102 if (m_view) {
103 m_view->setModel(m_model);
104 }
105
106 m_selectionManager->setModel(m_model);
107
108 emit modelChanged(m_model, oldModel);
109 }
110
111 KItemModelBase* KItemListController::model() const
112 {
113 return m_model;
114 }
115
116 KItemListSelectionManager* KItemListController::selectionManager() const
117 {
118 return m_selectionManager;
119 }
120
121 void KItemListController::setView(KItemListView* view)
122 {
123 if (m_view == view) {
124 return;
125 }
126
127 KItemListView* oldView = m_view;
128 if (oldView) {
129 disconnect(oldView, &KItemListView::scrollOffsetChanged, this, &KItemListController::slotViewScrollOffsetChanged);
130 oldView->deleteLater();
131 }
132
133 m_view = view;
134
135 if (m_view) {
136 m_view->setParent(this);
137 m_view->setController(this);
138 m_view->setModel(m_model);
139 connect(m_view, &KItemListView::scrollOffsetChanged, this, &KItemListController::slotViewScrollOffsetChanged);
140 updateExtendedSelectionRegion();
141 }
142
143 emit viewChanged(m_view, oldView);
144 }
145
146 KItemListView* KItemListController::view() const
147 {
148 return m_view;
149 }
150
151 void KItemListController::setSelectionBehavior(SelectionBehavior behavior)
152 {
153 m_selectionBehavior = behavior;
154 updateExtendedSelectionRegion();
155 }
156
157 KItemListController::SelectionBehavior KItemListController::selectionBehavior() const
158 {
159 return m_selectionBehavior;
160 }
161
162 void KItemListController::setAutoActivationBehavior(AutoActivationBehavior behavior)
163 {
164 m_autoActivationBehavior = behavior;
165 }
166
167 KItemListController::AutoActivationBehavior KItemListController::autoActivationBehavior() const
168 {
169 return m_autoActivationBehavior;
170 }
171
172 void KItemListController::setMouseDoubleClickAction(MouseDoubleClickAction action)
173 {
174 m_mouseDoubleClickAction = action;
175 }
176
177 KItemListController::MouseDoubleClickAction KItemListController::mouseDoubleClickAction() const
178 {
179 return m_mouseDoubleClickAction;
180 }
181
182 void KItemListController::setAutoActivationDelay(int delay)
183 {
184 m_autoActivationTimer->setInterval(delay);
185 }
186
187 int KItemListController::autoActivationDelay() const
188 {
189 return m_autoActivationTimer->interval();
190 }
191
192 void KItemListController::setSingleClickActivationEnforced(bool singleClick)
193 {
194 m_singleClickActivationEnforced = singleClick;
195 }
196
197 bool KItemListController::singleClickActivationEnforced() const
198 {
199 return m_singleClickActivationEnforced;
200 }
201
202 bool KItemListController::showEvent(QShowEvent* event)
203 {
204 Q_UNUSED(event);
205 return false;
206 }
207
208 bool KItemListController::hideEvent(QHideEvent* event)
209 {
210 Q_UNUSED(event);
211 return false;
212 }
213
214 bool KItemListController::keyPressEvent(QKeyEvent* event)
215 {
216 int index = m_selectionManager->currentItem();
217 int key = event->key();
218
219 // Handle the expanding/collapsing of items
220 if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
221 if (key == Qt::Key_Right) {
222 if (m_model->setExpanded(index, true)) {
223 return true;
224 }
225 } else if (key == Qt::Key_Left) {
226 if (m_model->setExpanded(index, false)) {
227 return true;
228 }
229 }
230 }
231
232 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
233 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
234 const bool shiftOrControlPressed = shiftPressed || controlPressed;
235
236 const int itemCount = m_model->count();
237
238 // For horizontal scroll orientation, transform
239 // the arrow keys to simplify the event handling.
240 if (m_view->scrollOrientation() == Qt::Horizontal) {
241 switch (key) {
242 case Qt::Key_Up: key = Qt::Key_Left; break;
243 case Qt::Key_Down: key = Qt::Key_Right; break;
244 case Qt::Key_Left: key = Qt::Key_Up; break;
245 case Qt::Key_Right: key = Qt::Key_Down; break;
246 default: break;
247 }
248 }
249
250 const bool selectSingleItem = m_selectionBehavior != NoSelection &&
251 itemCount == 1 &&
252 (key == Qt::Key_Home || key == Qt::Key_End ||
253 key == Qt::Key_Up || key == Qt::Key_Down ||
254 key == Qt::Key_Left || key == Qt::Key_Right);
255 if (selectSingleItem) {
256 const int current = m_selectionManager->currentItem();
257 m_selectionManager->setSelected(current);
258 return true;
259 }
260
261 switch (key) {
262 case Qt::Key_Home:
263 index = 0;
264 m_keyboardAnchorIndex = index;
265 m_keyboardAnchorPos = keyboardAnchorPos(index);
266 break;
267
268 case Qt::Key_End:
269 index = itemCount - 1;
270 m_keyboardAnchorIndex = index;
271 m_keyboardAnchorPos = keyboardAnchorPos(index);
272 break;
273
274 case Qt::Key_Left:
275 if (index > 0) {
276 const int expandedParentsCount = m_model->expandedParentsCount(index);
277 if (expandedParentsCount == 0) {
278 --index;
279 } else {
280 // Go to the parent of the current item.
281 do {
282 --index;
283 } while (index > 0 && m_model->expandedParentsCount(index) == expandedParentsCount);
284 }
285 m_keyboardAnchorIndex = index;
286 m_keyboardAnchorPos = keyboardAnchorPos(index);
287 }
288 break;
289
290 case Qt::Key_Right:
291 if (index < itemCount - 1) {
292 ++index;
293 m_keyboardAnchorIndex = index;
294 m_keyboardAnchorPos = keyboardAnchorPos(index);
295 }
296 break;
297
298 case Qt::Key_Up:
299 updateKeyboardAnchor();
300 index = previousRowIndex(index);
301 break;
302
303 case Qt::Key_Down:
304 updateKeyboardAnchor();
305 index = nextRowIndex(index);
306 break;
307
308 case Qt::Key_PageUp:
309 if (m_view->scrollOrientation() == Qt::Horizontal) {
310 // The new current index should correspond to the first item in the current column.
311 int newIndex = qMax(index - 1, 0);
312 while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() < m_view->itemRect(index).topLeft().y()) {
313 index = newIndex;
314 newIndex = qMax(index - 1, 0);
315 }
316 m_keyboardAnchorIndex = index;
317 m_keyboardAnchorPos = keyboardAnchorPos(index);
318 } else {
319 const qreal currentItemBottom = m_view->itemRect(index).bottomLeft().y();
320 const qreal height = m_view->geometry().height();
321
322 // The new current item should be the first item in the current
323 // column whose itemRect's top coordinate is larger than targetY.
324 const qreal targetY = currentItemBottom - height;
325
326 updateKeyboardAnchor();
327 int newIndex = previousRowIndex(index);
328 do {
329 index = newIndex;
330 updateKeyboardAnchor();
331 newIndex = previousRowIndex(index);
332 } while (m_view->itemRect(newIndex).topLeft().y() > targetY && newIndex != index);
333 }
334 break;
335
336 case Qt::Key_PageDown:
337 if (m_view->scrollOrientation() == Qt::Horizontal) {
338 // The new current index should correspond to the last item in the current column.
339 int newIndex = qMin(index + 1, m_model->count() - 1);
340 while (newIndex != index && m_view->itemRect(newIndex).topLeft().y() > m_view->itemRect(index).topLeft().y()) {
341 index = newIndex;
342 newIndex = qMin(index + 1, m_model->count() - 1);
343 }
344 m_keyboardAnchorIndex = index;
345 m_keyboardAnchorPos = keyboardAnchorPos(index);
346 } else {
347 const qreal currentItemTop = m_view->itemRect(index).topLeft().y();
348 const qreal height = m_view->geometry().height();
349
350 // The new current item should be the last item in the current
351 // column whose itemRect's bottom coordinate is smaller than targetY.
352 const qreal targetY = currentItemTop + height;
353
354 updateKeyboardAnchor();
355 int newIndex = nextRowIndex(index);
356 do {
357 index = newIndex;
358 updateKeyboardAnchor();
359 newIndex = nextRowIndex(index);
360 } while (m_view->itemRect(newIndex).bottomLeft().y() < targetY && newIndex != index);
361 }
362 break;
363
364 case Qt::Key_Enter:
365 case Qt::Key_Return: {
366 const KItemSet selectedItems = m_selectionManager->selectedItems();
367 if (selectedItems.count() >= 2) {
368 emit itemsActivated(selectedItems);
369 } else if (selectedItems.count() == 1) {
370 emit itemActivated(selectedItems.first());
371 } else {
372 emit itemActivated(index);
373 }
374 break;
375 }
376
377 case Qt::Key_Menu: {
378 // Emit the signal itemContextMenuRequested() in case if at least one
379 // item is selected. Otherwise the signal viewContextMenuRequested() will be emitted.
380 const KItemSet selectedItems = m_selectionManager->selectedItems();
381 int index = -1;
382 if (selectedItems.count() >= 2) {
383 const int currentItemIndex = m_selectionManager->currentItem();
384 index = selectedItems.contains(currentItemIndex)
385 ? currentItemIndex : selectedItems.first();
386 } else if (selectedItems.count() == 1) {
387 index = selectedItems.first();
388 }
389
390 if (index >= 0) {
391 const QRectF contextRect = m_view->itemContextRect(index);
392 const QPointF pos(m_view->scene()->views().first()->mapToGlobal(contextRect.bottomRight().toPoint()));
393 emit itemContextMenuRequested(index, pos);
394 } else {
395 emit viewContextMenuRequested(QCursor::pos());
396 }
397 break;
398 }
399
400 case Qt::Key_Escape:
401 if (m_selectionBehavior != SingleSelection) {
402 m_selectionManager->clearSelection();
403 }
404 m_keyboardManager->cancelSearch();
405 emit escapePressed();
406 break;
407
408 case Qt::Key_Space:
409 if (m_selectionBehavior == MultiSelection) {
410 if (controlPressed) {
411 // Toggle the selection state of the current item.
412 m_selectionManager->endAnchoredSelection();
413 m_selectionManager->setSelected(index, 1, KItemListSelectionManager::Toggle);
414 m_selectionManager->beginAnchoredSelection(index);
415 break;
416 } else {
417 // Select the current item if it is not selected yet.
418 const int current = m_selectionManager->currentItem();
419 if (!m_selectionManager->isSelected(current)) {
420 m_selectionManager->setSelected(current);
421 break;
422 }
423 }
424 }
425 // Fall through to the default case and add the Space to the current search string.
426
427 default:
428 m_keyboardManager->addKeys(event->text());
429 // Make sure unconsumed events get propagated up the chain. #302329
430 event->ignore();
431 return false;
432 }
433
434 if (m_selectionManager->currentItem() != index) {
435 switch (m_selectionBehavior) {
436 case NoSelection:
437 m_selectionManager->setCurrentItem(index);
438 break;
439
440 case SingleSelection:
441 m_selectionManager->setCurrentItem(index);
442 m_selectionManager->clearSelection();
443 m_selectionManager->setSelected(index, 1);
444 break;
445
446 case MultiSelection:
447 if (controlPressed) {
448 m_selectionManager->endAnchoredSelection();
449 }
450
451 m_selectionManager->setCurrentItem(index);
452
453 if (!shiftOrControlPressed) {
454 m_selectionManager->clearSelection();
455 m_selectionManager->setSelected(index, 1);
456 }
457
458 if (!shiftPressed) {
459 m_selectionManager->beginAnchoredSelection(index);
460 }
461 break;
462 }
463
464 m_view->scrollToItem(index);
465 }
466 return true;
467 }
468
469 void KItemListController::slotChangeCurrentItem(const QString& text, bool searchFromNextItem)
470 {
471 if (!m_model || m_model->count() == 0) {
472 return;
473 }
474 const int currentIndex = m_selectionManager->currentItem();
475 int index;
476 if (searchFromNextItem) {
477 index = m_model->indexForKeyboardSearch(text, (currentIndex + 1) % m_model->count());
478 } else {
479 index = m_model->indexForKeyboardSearch(text, currentIndex);
480 }
481 if (index >= 0) {
482 m_selectionManager->setCurrentItem(index);
483
484 if (m_selectionBehavior != NoSelection) {
485 m_selectionManager->clearSelection();
486 m_selectionManager->setSelected(index, 1);
487 m_selectionManager->beginAnchoredSelection(index);
488 }
489
490 m_view->scrollToItem(index);
491 }
492 }
493
494 void KItemListController::slotAutoActivationTimeout()
495 {
496 if (!m_model || !m_view) {
497 return;
498 }
499
500 const int index = m_autoActivationTimer->property("index").toInt();
501 if (index < 0 || index >= m_model->count()) {
502 return;
503 }
504
505 /* m_view->isUnderMouse() fixes a bug in the Folder-View-Panel and in the
506 * Places-Panel.
507 *
508 * Bug: When you drag a file onto a Folder-View-Item or a Places-Item and
509 * then move away before the auto-activation timeout triggers, than the
510 * item still becomes activated/expanded.
511 *
512 * See Bug 293200 and 305783
513 */
514 if (m_model->supportsDropping(index) && m_view->isUnderMouse()) {
515 if (m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
516 const bool expanded = m_model->isExpanded(index);
517 m_model->setExpanded(index, !expanded);
518 } else if (m_autoActivationBehavior != ExpansionOnly) {
519 emit itemActivated(index);
520 }
521 }
522 }
523
524 bool KItemListController::inputMethodEvent(QInputMethodEvent* event)
525 {
526 Q_UNUSED(event);
527 return false;
528 }
529
530 bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
531 {
532 if (!m_view) {
533 return false;
534 }
535
536 m_pressedMousePos = transform.map(event->pos());
537 m_pressedIndex = m_view->itemAt(m_pressedMousePos);
538 emit mouseButtonPressed(m_pressedIndex, event->buttons());
539
540 if (event->buttons() & (Qt::BackButton | Qt::ForwardButton)) {
541 // Do not select items when clicking the back/forward buttons, see
542 // https://bugs.kde.org/show_bug.cgi?id=327412.
543 return true;
544 }
545
546 if (m_view->isAboveExpansionToggle(m_pressedIndex, m_pressedMousePos)) {
547 m_selectionManager->endAnchoredSelection();
548 m_selectionManager->setCurrentItem(m_pressedIndex);
549 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
550 return true;
551 }
552
553 m_selectionTogglePressed = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos);
554 if (m_selectionTogglePressed) {
555 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
556 // The previous anchored selection has been finished already in
557 // KItemListSelectionManager::setSelected(). We can safely change
558 // the current item and start a new anchored selection now.
559 m_selectionManager->setCurrentItem(m_pressedIndex);
560 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
561 return true;
562 }
563
564 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
565 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
566
567 // The previous selection is cleared if either
568 // 1. The selection mode is SingleSelection, or
569 // 2. the selection mode is MultiSelection, and *none* of the following conditions are met:
570 // a) Shift or Control are pressed.
571 // b) The clicked item is selected already. In that case, the user might want to:
572 // - start dragging multiple items, or
573 // - open the context menu and perform an action for all selected items.
574 const bool shiftOrControlPressed = shiftPressed || controlPressed;
575 const bool pressedItemAlreadySelected = m_pressedIndex >= 0 && m_selectionManager->isSelected(m_pressedIndex);
576 const bool clearSelection = m_selectionBehavior == SingleSelection ||
577 (!shiftOrControlPressed && !pressedItemAlreadySelected);
578 if (clearSelection) {
579 m_selectionManager->clearSelection();
580 } else if (pressedItemAlreadySelected && !shiftOrControlPressed && (event->buttons() & Qt::LeftButton)) {
581 // The user might want to start dragging multiple items, but if he clicks the item
582 // in order to trigger it instead, the other selected items must be deselected.
583 // However, we do not know yet what the user is going to do.
584 // -> remember that the user pressed an item which had been selected already and
585 // clear the selection in mouseReleaseEvent(), unless the items are dragged.
586 m_clearSelectionIfItemsAreNotDragged = true;
587
588 if (m_selectionManager->selectedItems().count() == 1 && m_view->isAboveText(m_pressedIndex, m_pressedMousePos)) {
589 emit selectedItemTextPressed(m_pressedIndex);
590 }
591 }
592
593 if (!shiftPressed) {
594 // Finish the anchored selection before the current index is changed
595 m_selectionManager->endAnchoredSelection();
596 }
597
598 if (m_pressedIndex >= 0) {
599 m_selectionManager->setCurrentItem(m_pressedIndex);
600
601 switch (m_selectionBehavior) {
602 case NoSelection:
603 break;
604
605 case SingleSelection:
606 m_selectionManager->setSelected(m_pressedIndex);
607 break;
608
609 case MultiSelection:
610 if (controlPressed && !shiftPressed) {
611 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
612 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
613 } else if (!shiftPressed || !m_selectionManager->isAnchoredSelectionActive()) {
614 // Select the pressed item and start a new anchored selection
615 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select);
616 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
617 }
618 break;
619
620 default:
621 Q_ASSERT(false);
622 break;
623 }
624
625 if (event->buttons() & Qt::RightButton) {
626 emit itemContextMenuRequested(m_pressedIndex, event->screenPos());
627 }
628
629 return true;
630 }
631
632 if (event->buttons() & Qt::RightButton) {
633 const QRectF headerBounds = m_view->headerBoundaries();
634 if (headerBounds.contains(event->pos())) {
635 emit headerContextMenuRequested(event->screenPos());
636 } else {
637 emit viewContextMenuRequested(event->screenPos());
638 }
639 return true;
640 }
641
642 if (m_selectionBehavior == MultiSelection) {
643 QPointF startPos = m_pressedMousePos;
644 if (m_view->scrollOrientation() == Qt::Vertical) {
645 startPos.ry() += m_view->scrollOffset();
646 if (m_view->itemSize().width() < 0) {
647 // Use a special rubberband for views that have only one column and
648 // expand the rubberband to use the whole width of the view.
649 startPos.setX(0);
650 }
651 } else {
652 startPos.rx() += m_view->scrollOffset();
653 }
654
655 m_oldSelection = m_selectionManager->selectedItems();
656 KItemListRubberBand* rubberBand = m_view->rubberBand();
657 rubberBand->setStartPosition(startPos);
658 rubberBand->setEndPosition(startPos);
659 rubberBand->setActive(true);
660 connect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
661 m_view->setAutoScroll(true);
662 }
663
664 return false;
665 }
666
667 bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
668 {
669 if (!m_view) {
670 return false;
671 }
672
673 if (m_pressedIndex >= 0) {
674 // Check whether a dragging should be started
675 if (event->buttons() & Qt::LeftButton) {
676 const QPointF pos = transform.map(event->pos());
677 if ((pos - m_pressedMousePos).manhattanLength() >= QApplication::startDragDistance()) {
678 if (!m_selectionManager->isSelected(m_pressedIndex)) {
679 // Always assure that the dragged item gets selected. Usually this is already
680 // done on the mouse-press event, but when using the selection-toggle on a
681 // selected item the dragged item is not selected yet.
682 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
683 } else {
684 // A selected item has been clicked to drag all selected items
685 // -> the selection should not be cleared when the mouse button is released.
686 m_clearSelectionIfItemsAreNotDragged = false;
687 }
688
689 startDragging();
690 }
691 }
692 } else {
693 KItemListRubberBand* rubberBand = m_view->rubberBand();
694 if (rubberBand->isActive()) {
695 QPointF endPos = transform.map(event->pos());
696
697 // Update the current item.
698 const int newCurrent = m_view->itemAt(endPos);
699 if (newCurrent >= 0) {
700 // It's expected that the new current index is also the new anchor (bug 163451).
701 m_selectionManager->endAnchoredSelection();
702 m_selectionManager->setCurrentItem(newCurrent);
703 m_selectionManager->beginAnchoredSelection(newCurrent);
704 }
705
706 if (m_view->scrollOrientation() == Qt::Vertical) {
707 endPos.ry() += m_view->scrollOffset();
708 if (m_view->itemSize().width() < 0) {
709 // Use a special rubberband for views that have only one column and
710 // expand the rubberband to use the whole width of the view.
711 endPos.setX(m_view->size().width());
712 }
713 } else {
714 endPos.rx() += m_view->scrollOffset();
715 }
716 rubberBand->setEndPosition(endPos);
717 }
718 }
719
720 return false;
721 }
722
723 bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
724 {
725 if (!m_view) {
726 return false;
727 }
728
729 emit mouseButtonReleased(m_pressedIndex, event->buttons());
730
731 const bool isAboveSelectionToggle = m_view->isAboveSelectionToggle(m_pressedIndex, m_pressedMousePos);
732 if (isAboveSelectionToggle) {
733 m_selectionTogglePressed = false;
734 return true;
735 }
736
737 if (!isAboveSelectionToggle && m_selectionTogglePressed) {
738 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
739 m_selectionTogglePressed = false;
740 return true;
741 }
742
743 const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier ||
744 event->modifiers() & Qt::ControlModifier;
745
746 KItemListRubberBand* rubberBand = m_view->rubberBand();
747 if (rubberBand->isActive()) {
748 disconnect(rubberBand, &KItemListRubberBand::endPositionChanged, this, &KItemListController::slotRubberBandChanged);
749 rubberBand->setActive(false);
750 m_oldSelection.clear();
751 m_view->setAutoScroll(false);
752 }
753
754 const QPointF pos = transform.map(event->pos());
755 const int index = m_view->itemAt(pos);
756
757 if (index >= 0 && index == m_pressedIndex) {
758 // The release event is done above the same item as the press event
759
760 if (m_clearSelectionIfItemsAreNotDragged) {
761 // A selected item has been clicked, but no drag operation has been started
762 // -> clear the rest of the selection.
763 m_selectionManager->clearSelection();
764 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select);
765 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
766 }
767
768 if (event->button() & Qt::LeftButton) {
769 bool emitItemActivated = true;
770 if (m_view->isAboveExpansionToggle(index, pos)) {
771 const bool expanded = m_model->isExpanded(index);
772 m_model->setExpanded(index, !expanded);
773
774 emit itemExpansionToggleClicked(index);
775 emitItemActivated = false;
776 } else if (shiftOrControlPressed) {
777 // The mouse click should only update the selection, not trigger the item
778 emitItemActivated = false;
779 } else if (!(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced)) {
780 emitItemActivated = false;
781 }
782 if (emitItemActivated) {
783 emit itemActivated(index);
784 }
785 } else if (event->button() & Qt::MidButton) {
786 emit itemMiddleClicked(index);
787 }
788 }
789
790 m_pressedMousePos = QPointF();
791 m_pressedIndex = -1;
792 m_clearSelectionIfItemsAreNotDragged = false;
793 return false;
794 }
795
796 bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
797 {
798 const QPointF pos = transform.map(event->pos());
799 const int index = m_view->itemAt(pos);
800
801 // Expand item if desired - See Bug 295573
802 if (m_mouseDoubleClickAction != ActivateItemOnly) {
803 if (m_view && m_model && m_view->supportsItemExpanding() && m_model->isExpandable(index)) {
804 const bool expanded = m_model->isExpanded(index);
805 m_model->setExpanded(index, !expanded);
806 }
807 }
808
809 if (event->button() & Qt::RightButton) {
810 m_selectionManager->clearSelection();
811 if (index >= 0) {
812 m_selectionManager->setSelected(index);
813 emit itemContextMenuRequested(index, event->screenPos());
814 } else {
815 const QRectF headerBounds = m_view->headerBoundaries();
816 if (headerBounds.contains(event->pos())) {
817 emit headerContextMenuRequested(event->screenPos());
818 } else {
819 emit viewContextMenuRequested(event->screenPos());
820 }
821 }
822 return true;
823 }
824
825 bool emitItemActivated = !(m_view->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) || m_singleClickActivationEnforced) &&
826 (event->button() & Qt::LeftButton) &&
827 index >= 0 && index < m_model->count();
828 if (emitItemActivated) {
829 emit itemActivated(index);
830 }
831 return false;
832 }
833
834 bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
835 {
836 Q_UNUSED(event);
837 Q_UNUSED(transform);
838 return false;
839 }
840
841 bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
842 {
843 Q_UNUSED(event);
844 Q_UNUSED(transform);
845
846 m_autoActivationTimer->stop();
847 m_view->setAutoScroll(false);
848 m_view->hideDropIndicator();
849
850 KItemListWidget* widget = hoveredWidget();
851 if (widget) {
852 widget->setHovered(false);
853 emit itemUnhovered(widget->index());
854 }
855 return false;
856 }
857
858 bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
859 {
860 if (!m_model || !m_view) {
861 return false;
862 }
863
864
865 QUrl hoveredDir = m_model->directory();
866 KItemListWidget* oldHoveredWidget = hoveredWidget();
867
868 const QPointF pos = transform.map(event->pos());
869 KItemListWidget* newHoveredWidget = widgetForPos(pos);
870
871 if (oldHoveredWidget != newHoveredWidget) {
872 m_autoActivationTimer->stop();
873
874 if (oldHoveredWidget) {
875 oldHoveredWidget->setHovered(false);
876 emit itemUnhovered(oldHoveredWidget->index());
877 }
878 }
879
880 if (newHoveredWidget) {
881 bool droppingBetweenItems = false;
882 if (m_model->sortRole().isEmpty()) {
883 // The model supports inserting items between other items.
884 droppingBetweenItems = (m_view->showDropIndicator(pos) >= 0);
885 }
886
887 const int index = newHoveredWidget->index();
888
889 if (m_model->isDir(index)) {
890 hoveredDir = m_model->url(index);
891 }
892
893 if (!droppingBetweenItems) {
894 if (m_model->supportsDropping(index)) {
895 // Something has been dragged on an item.
896 m_view->hideDropIndicator();
897 if (!newHoveredWidget->isHovered()) {
898 newHoveredWidget->setHovered(true);
899 emit itemHovered(index);
900 }
901
902 if (!m_autoActivationTimer->isActive() && m_autoActivationTimer->interval() >= 0) {
903 m_autoActivationTimer->setProperty("index", index);
904 m_autoActivationTimer->start();
905 }
906 }
907 } else {
908 m_autoActivationTimer->stop();
909 if (newHoveredWidget && newHoveredWidget->isHovered()) {
910 newHoveredWidget->setHovered(false);
911 emit itemUnhovered(index);
912 }
913 }
914 } else {
915 m_view->hideDropIndicator();
916 }
917
918 event->setAccepted(!DragAndDropHelper::urlListMatchesUrl(event->mimeData()->urls(), hoveredDir));
919
920 return false;
921 }
922
923 bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
924 {
925 if (!m_view) {
926 return false;
927 }
928
929 m_autoActivationTimer->stop();
930 m_view->setAutoScroll(false);
931
932 const QPointF pos = transform.map(event->pos());
933
934 int dropAboveIndex = -1;
935 if (m_model->sortRole().isEmpty()) {
936 // The model supports inserting of items between other items.
937 dropAboveIndex = m_view->showDropIndicator(pos);
938 }
939
940 if (dropAboveIndex >= 0) {
941 // Something has been dropped between two items.
942 m_view->hideDropIndicator();
943 emit aboveItemDropEvent(dropAboveIndex, event);
944 } else if (!event->mimeData()->hasFormat(m_model->blacklistItemDropEventMimeType())) {
945 // Something has been dropped on an item or on an empty part of the view.
946 emit itemDropEvent(m_view->itemAt(pos), event);
947 }
948
949 QAccessibleEvent accessibilityEvent(view(), QAccessible::DragDropEnd);
950 QAccessible::updateAccessibility(&accessibilityEvent);
951
952 return true;
953 }
954
955 bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
956 {
957 Q_UNUSED(event);
958 Q_UNUSED(transform);
959 return false;
960 }
961
962 bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
963 {
964 Q_UNUSED(transform);
965 if (!m_model || !m_view) {
966 return false;
967 }
968
969 KItemListWidget* oldHoveredWidget = hoveredWidget();
970 const QPointF pos = transform.map(event->pos());
971 KItemListWidget* newHoveredWidget = widgetForPos(pos);
972
973 if (oldHoveredWidget != newHoveredWidget) {
974 if (oldHoveredWidget) {
975 oldHoveredWidget->setHovered(false);
976 emit itemUnhovered(oldHoveredWidget->index());
977 }
978
979 if (newHoveredWidget) {
980 newHoveredWidget->setHovered(true);
981 const QPointF mappedPos = newHoveredWidget->mapFromItem(m_view, pos);
982 newHoveredWidget->setHoverPosition(mappedPos);
983 emit itemHovered(newHoveredWidget->index());
984 }
985 } else if (oldHoveredWidget) {
986 const QPointF mappedPos = oldHoveredWidget->mapFromItem(m_view, pos);
987 oldHoveredWidget->setHoverPosition(mappedPos);
988 }
989
990 return false;
991 }
992
993 bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
994 {
995 Q_UNUSED(event);
996 Q_UNUSED(transform);
997
998 if (!m_model || !m_view) {
999 return false;
1000 }
1001
1002 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
1003 if (widget->isHovered()) {
1004 widget->setHovered(false);
1005 emit itemUnhovered(widget->index());
1006 }
1007 }
1008 return false;
1009 }
1010
1011 bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
1012 {
1013 Q_UNUSED(event);
1014 Q_UNUSED(transform);
1015 return false;
1016 }
1017
1018 bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
1019 {
1020 Q_UNUSED(event);
1021 Q_UNUSED(transform);
1022 return false;
1023 }
1024
1025 bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
1026 {
1027 if (!event) {
1028 return false;
1029 }
1030
1031 switch (event->type()) {
1032 case QEvent::KeyPress:
1033 return keyPressEvent(static_cast<QKeyEvent*>(event));
1034 case QEvent::InputMethod:
1035 return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
1036 case QEvent::GraphicsSceneMousePress:
1037 return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
1038 case QEvent::GraphicsSceneMouseMove:
1039 return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
1040 case QEvent::GraphicsSceneMouseRelease:
1041 return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
1042 case QEvent::GraphicsSceneMouseDoubleClick:
1043 return mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
1044 case QEvent::GraphicsSceneWheel:
1045 return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
1046 case QEvent::GraphicsSceneDragEnter:
1047 return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
1048 case QEvent::GraphicsSceneDragLeave:
1049 return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
1050 case QEvent::GraphicsSceneDragMove:
1051 return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
1052 case QEvent::GraphicsSceneDrop:
1053 return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
1054 case QEvent::GraphicsSceneHoverEnter:
1055 return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
1056 case QEvent::GraphicsSceneHoverMove:
1057 return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
1058 case QEvent::GraphicsSceneHoverLeave:
1059 return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
1060 case QEvent::GraphicsSceneResize:
1061 return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
1062 default:
1063 break;
1064 }
1065
1066 return false;
1067 }
1068
1069 void KItemListController::slotViewScrollOffsetChanged(qreal current, qreal previous)
1070 {
1071 if (!m_view) {
1072 return;
1073 }
1074
1075 KItemListRubberBand* rubberBand = m_view->rubberBand();
1076 if (rubberBand->isActive()) {
1077 const qreal diff = current - previous;
1078 // TODO: Ideally just QCursor::pos() should be used as
1079 // new end-position but it seems there is no easy way
1080 // to have something like QWidget::mapFromGlobal() for QGraphicsWidget
1081 // (... or I just missed an easy way to do the mapping)
1082 QPointF endPos = rubberBand->endPosition();
1083 if (m_view->scrollOrientation() == Qt::Vertical) {
1084 endPos.ry() += diff;
1085 } else {
1086 endPos.rx() += diff;
1087 }
1088
1089 rubberBand->setEndPosition(endPos);
1090 }
1091 }
1092
1093 void KItemListController::slotRubberBandChanged()
1094 {
1095 if (!m_view || !m_model || m_model->count() <= 0) {
1096 return;
1097 }
1098
1099 const KItemListRubberBand* rubberBand = m_view->rubberBand();
1100 const QPointF startPos = rubberBand->startPosition();
1101 const QPointF endPos = rubberBand->endPosition();
1102 QRectF rubberBandRect = QRectF(startPos, endPos).normalized();
1103
1104 const bool scrollVertical = (m_view->scrollOrientation() == Qt::Vertical);
1105 if (scrollVertical) {
1106 rubberBandRect.translate(0, -m_view->scrollOffset());
1107 } else {
1108 rubberBandRect.translate(-m_view->scrollOffset(), 0);
1109 }
1110
1111 if (!m_oldSelection.isEmpty()) {
1112 // Clear the old selection that was available before the rubberband has
1113 // been activated in case if no Shift- or Control-key are pressed
1114 const bool shiftOrControlPressed = QApplication::keyboardModifiers() & Qt::ShiftModifier ||
1115 QApplication::keyboardModifiers() & Qt::ControlModifier;
1116 if (!shiftOrControlPressed) {
1117 m_oldSelection.clear();
1118 }
1119 }
1120
1121 KItemSet selectedItems;
1122
1123 // Select all visible items that intersect with the rubberband
1124 foreach (const KItemListWidget* widget, m_view->visibleItemListWidgets()) {
1125 const int index = widget->index();
1126
1127 const QRectF widgetRect = m_view->itemRect(index);
1128 if (widgetRect.intersects(rubberBandRect)) {
1129 const QRectF iconRect = widget->iconRect().translated(widgetRect.topLeft());
1130 const QRectF textRect = widget->textRect().translated(widgetRect.topLeft());
1131 if (iconRect.intersects(rubberBandRect) || textRect.intersects(rubberBandRect)) {
1132 selectedItems.insert(index);
1133 }
1134 }
1135 }
1136
1137 // Select all invisible items that intersect with the rubberband. Instead of
1138 // iterating all items only the area which might be touched by the rubberband
1139 // will be checked.
1140 const bool increaseIndex = scrollVertical ?
1141 startPos.y() > endPos.y(): startPos.x() > endPos.x();
1142
1143 int index = increaseIndex ? m_view->lastVisibleIndex() + 1 : m_view->firstVisibleIndex() - 1;
1144 bool selectionFinished = false;
1145 do {
1146 const QRectF widgetRect = m_view->itemRect(index);
1147 if (widgetRect.intersects(rubberBandRect)) {
1148 selectedItems.insert(index);
1149 }
1150
1151 if (increaseIndex) {
1152 ++index;
1153 selectionFinished = (index >= m_model->count()) ||
1154 ( scrollVertical && widgetRect.top() > rubberBandRect.bottom()) ||
1155 (!scrollVertical && widgetRect.left() > rubberBandRect.right());
1156 } else {
1157 --index;
1158 selectionFinished = (index < 0) ||
1159 ( scrollVertical && widgetRect.bottom() < rubberBandRect.top()) ||
1160 (!scrollVertical && widgetRect.right() < rubberBandRect.left());
1161 }
1162 } while (!selectionFinished);
1163
1164 if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
1165 // If Control is pressed, the selection state of all items in the rubberband is toggled.
1166 // Therefore, the new selection contains:
1167 // 1. All previously selected items which are not inside the rubberband, and
1168 // 2. all items inside the rubberband which have not been selected previously.
1169 m_selectionManager->setSelectedItems(m_oldSelection ^ selectedItems);
1170 }
1171 else {
1172 m_selectionManager->setSelectedItems(selectedItems + m_oldSelection);
1173 }
1174 }
1175
1176 void KItemListController::startDragging()
1177 {
1178 if (!m_view || !m_model) {
1179 return;
1180 }
1181
1182 const KItemSet selectedItems = m_selectionManager->selectedItems();
1183 if (selectedItems.isEmpty()) {
1184 return;
1185 }
1186
1187 QMimeData* data = m_model->createMimeData(selectedItems);
1188 if (!data) {
1189 return;
1190 }
1191
1192 // The created drag object will be owned and deleted
1193 // by QApplication::activeWindow().
1194 QDrag* drag = new QDrag(QApplication::activeWindow());
1195 drag->setMimeData(data);
1196
1197 const QPixmap pixmap = m_view->createDragPixmap(selectedItems);
1198 drag->setPixmap(pixmap);
1199
1200 const QPoint hotSpot((pixmap.width() / pixmap.devicePixelRatio()) / 2, 0);
1201 drag->setHotSpot(hotSpot);
1202
1203 drag->exec(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction, Qt::CopyAction);
1204
1205 QAccessibleEvent accessibilityEvent(view(), QAccessible::DragDropStart);
1206 QAccessible::updateAccessibility(&accessibilityEvent);
1207 }
1208
1209 KItemListWidget* KItemListController::hoveredWidget() const
1210 {
1211 Q_ASSERT(m_view);
1212
1213 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
1214 if (widget->isHovered()) {
1215 return widget;
1216 }
1217 }
1218
1219 return 0;
1220 }
1221
1222 KItemListWidget* KItemListController::widgetForPos(const QPointF& pos) const
1223 {
1224 Q_ASSERT(m_view);
1225
1226 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
1227 const QPointF mappedPos = widget->mapFromItem(m_view, pos);
1228
1229 const bool hovered = widget->contains(mappedPos) &&
1230 !widget->expansionToggleRect().contains(mappedPos);
1231 if (hovered) {
1232 return widget;
1233 }
1234 }
1235
1236 return 0;
1237 }
1238
1239 void KItemListController::updateKeyboardAnchor()
1240 {
1241 const bool validAnchor = m_keyboardAnchorIndex >= 0 &&
1242 m_keyboardAnchorIndex < m_model->count() &&
1243 keyboardAnchorPos(m_keyboardAnchorIndex) == m_keyboardAnchorPos;
1244 if (!validAnchor) {
1245 const int index = m_selectionManager->currentItem();
1246 m_keyboardAnchorIndex = index;
1247 m_keyboardAnchorPos = keyboardAnchorPos(index);
1248 }
1249 }
1250
1251 int KItemListController::nextRowIndex(int index) const
1252 {
1253 if (m_keyboardAnchorIndex < 0) {
1254 return index;
1255 }
1256
1257 const int maxIndex = m_model->count() - 1;
1258 if (index == maxIndex) {
1259 return index;
1260 }
1261
1262 // Calculate the index of the last column inside the row of the current index
1263 int lastColumnIndex = index;
1264 while (keyboardAnchorPos(lastColumnIndex + 1) > keyboardAnchorPos(lastColumnIndex)) {
1265 ++lastColumnIndex;
1266 if (lastColumnIndex >= maxIndex) {
1267 return index;
1268 }
1269 }
1270
1271 // Based on the last column index go to the next row and calculate the nearest index
1272 // that is below the current index
1273 int nextRowIndex = lastColumnIndex + 1;
1274 int searchIndex = nextRowIndex;
1275 qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(nextRowIndex));
1276 while (searchIndex < maxIndex && keyboardAnchorPos(searchIndex + 1) > keyboardAnchorPos(searchIndex)) {
1277 ++searchIndex;
1278 const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
1279 if (searchDiff < minDiff) {
1280 minDiff = searchDiff;
1281 nextRowIndex = searchIndex;
1282 }
1283 }
1284
1285 return nextRowIndex;
1286 }
1287
1288 int KItemListController::previousRowIndex(int index) const
1289 {
1290 if (m_keyboardAnchorIndex < 0 || index == 0) {
1291 return index;
1292 }
1293
1294 // Calculate the index of the first column inside the row of the current index
1295 int firstColumnIndex = index;
1296 while (keyboardAnchorPos(firstColumnIndex - 1) < keyboardAnchorPos(firstColumnIndex)) {
1297 --firstColumnIndex;
1298 if (firstColumnIndex <= 0) {
1299 return index;
1300 }
1301 }
1302
1303 // Based on the first column index go to the previous row and calculate the nearest index
1304 // that is above the current index
1305 int previousRowIndex = firstColumnIndex - 1;
1306 int searchIndex = previousRowIndex;
1307 qreal minDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(previousRowIndex));
1308 while (searchIndex > 0 && keyboardAnchorPos(searchIndex - 1) < keyboardAnchorPos(searchIndex)) {
1309 --searchIndex;
1310 const qreal searchDiff = qAbs(m_keyboardAnchorPos - keyboardAnchorPos(searchIndex));
1311 if (searchDiff < minDiff) {
1312 minDiff = searchDiff;
1313 previousRowIndex = searchIndex;
1314 }
1315 }
1316
1317 return previousRowIndex;
1318 }
1319
1320 qreal KItemListController::keyboardAnchorPos(int index) const
1321 {
1322 const QRectF itemRect = m_view->itemRect(index);
1323 if (!itemRect.isEmpty()) {
1324 return (m_view->scrollOrientation() == Qt::Vertical) ? itemRect.x() : itemRect.y();
1325 }
1326
1327 return 0;
1328 }
1329
1330 void KItemListController::updateExtendedSelectionRegion()
1331 {
1332 if (m_view) {
1333 const bool extend = (m_selectionBehavior != MultiSelection);
1334 KItemListStyleOption option = m_view->styleOption();
1335 if (option.extendedSelectionRegion != extend) {
1336 option.extendedSelectionRegion = extend;
1337 m_view->setStyleOption(option);
1338 }
1339 }
1340 }
1341