]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemlistcontroller.cpp
Implement selection of items using mouse clicks.
[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 "kitemlistselectionmanager.h"
27
28 #include <QEvent>
29 #include <QGraphicsSceneEvent>
30 #include <QTransform>
31
32 #include <KDebug>
33
34 KItemListController::KItemListController(QObject* parent) :
35 QObject(parent),
36 m_selectionBehavior(NoSelection),
37 m_model(0),
38 m_view(0),
39 m_selectionManager(new KItemListSelectionManager(this)),
40 m_pressedIndex(-1)
41 {
42 }
43
44 KItemListController::~KItemListController()
45 {
46 }
47
48 void KItemListController::setModel(KItemModelBase* model)
49 {
50 if (m_model == model) {
51 return;
52 }
53
54 KItemModelBase* oldModel = m_model;
55 m_model = model;
56
57 if (m_view) {
58 m_view->setModel(m_model);
59 }
60
61 m_selectionManager->setModel(m_model);
62
63 emit modelChanged(m_model, oldModel);
64 }
65
66 KItemModelBase* KItemListController::model() const
67 {
68 return m_model;
69 }
70
71 KItemListSelectionManager* KItemListController::selectionManager() const
72 {
73 return m_selectionManager;
74 }
75
76 void KItemListController::setView(KItemListView* view)
77 {
78 if (m_view == view) {
79 return;
80 }
81
82 KItemListView* oldView = m_view;
83 m_view = view;
84
85 if (m_view) {
86 m_view->setController(this);
87 m_view->setModel(m_model);
88 }
89
90 emit viewChanged(m_view, oldView);
91 }
92
93 KItemListView* KItemListController::view() const
94 {
95 return m_view;
96 }
97
98 void KItemListController::setSelectionBehavior(SelectionBehavior behavior)
99 {
100 m_selectionBehavior = behavior;
101 }
102
103 KItemListController::SelectionBehavior KItemListController::selectionBehavior() const
104 {
105 return m_selectionBehavior;
106 }
107
108 bool KItemListController::showEvent(QShowEvent* event)
109 {
110 Q_UNUSED(event);
111 return false;
112 }
113
114 bool KItemListController::hideEvent(QHideEvent* event)
115 {
116 Q_UNUSED(event);
117 return false;
118 }
119
120 bool KItemListController::keyPressEvent(QKeyEvent* event)
121 {
122 switch (event->key()) {
123 case Qt::Key_Home:
124 m_selectionManager->setCurrentItem(0);
125 break;
126 case Qt::Key_End:
127 m_selectionManager->setCurrentItem(m_model->count() - 1);
128 break;
129 }
130 return false;
131 }
132
133 bool KItemListController::inputMethodEvent(QInputMethodEvent* event)
134 {
135 Q_UNUSED(event);
136 return false;
137 }
138
139 bool KItemListController::mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
140 {
141 const QPointF pos = transform.map(event->pos());
142 m_pressedIndex = m_view->itemAt(pos);
143
144 if (m_view->isAboveExpansionToggle(m_pressedIndex, pos)) {
145 return true;
146 }
147
148 const bool shiftPressed = event->modifiers() & Qt::ShiftModifier;
149 const bool controlPressed = event->modifiers() & Qt::ControlModifier;
150 const bool shiftOrControlPressed = shiftPressed || controlPressed;
151
152 if (!shiftOrControlPressed || m_selectionBehavior == SingleSelection) {
153 m_selectionManager->clearSelection();
154 }
155
156 if (!shiftPressed) {
157 // Finish the anchored selection before the current index is changed
158 m_selectionManager->endAnchoredSelection();
159 }
160
161 if (m_pressedIndex >= 0) {
162 m_selectionManager->setCurrentItem(m_pressedIndex);
163
164 switch (m_selectionBehavior) {
165 case NoSelection:
166 return true;
167 case SingleSelection:
168 m_selectionManager->setSelected(m_pressedIndex);
169 return true;
170 case MultiSelection:
171 if (controlPressed) {
172 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Toggle);
173 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
174 }
175 else {
176 if (shiftPressed && m_selectionManager->isAnchoredSelectionActive()) {
177 // The anchored selection is continued automatically by calling
178 // m_selectionManager->setCurrentItem(m_pressedIndex), see above -> nothing more to do here
179 return true;
180 }
181
182 // Select the pressed item and start a new anchored selection
183 m_selectionManager->setSelected(m_pressedIndex, 1, KItemListSelectionManager::Select);
184 m_selectionManager->beginAnchoredSelection(m_pressedIndex);
185 }
186 }
187
188 return true;
189 }
190
191 return false;
192 }
193
194 bool KItemListController::mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
195 {
196 Q_UNUSED(event);
197 Q_UNUSED(transform);
198 return false;
199 }
200
201 bool KItemListController::mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
202 {
203 if (m_view) {
204 const QPointF pos = transform.map(event->pos());
205 const int index = m_view->itemAt(pos);
206 const bool shiftOrControlPressed = event->modifiers() & Qt::ShiftModifier || event->modifiers() & Qt::ControlModifier;
207
208 if (index >= 0 && index == m_pressedIndex) {
209 // The release event is done above the same item as the press event
210 bool emitItemClicked = true;
211 if (event->button() & Qt::LeftButton) {
212 if (m_view->isAboveExpansionToggle(index, pos)) {
213 emit itemExpansionToggleClicked(index);
214 emitItemClicked = false;
215 }
216 else if (shiftOrControlPressed) {
217 // The mouse click should only update the selection, not trigger the item
218 emitItemClicked = false;
219 }
220 }
221
222 if (emitItemClicked) {
223 emit itemClicked(index, event->button());
224 }
225 } else if (!shiftOrControlPressed) {
226 m_selectionManager->clearSelection();
227 }
228 }
229
230 m_pressedIndex = -1;
231 return false;
232 }
233
234 bool KItemListController::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform)
235 {
236 Q_UNUSED(event);
237 Q_UNUSED(transform);
238 return false;
239 }
240
241 bool KItemListController::dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
242 {
243 Q_UNUSED(event);
244 Q_UNUSED(transform);
245 return false;
246 }
247
248 bool KItemListController::dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
249 {
250 Q_UNUSED(event);
251 Q_UNUSED(transform);
252 return false;
253 }
254
255 bool KItemListController::dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
256 {
257 Q_UNUSED(event);
258 Q_UNUSED(transform);
259 return false;
260 }
261
262 bool KItemListController::dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform)
263 {
264 Q_UNUSED(event);
265 Q_UNUSED(transform);
266 return false;
267 }
268
269 bool KItemListController::hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
270 {
271 Q_UNUSED(event);
272 Q_UNUSED(transform);
273 return false;
274 }
275
276 bool KItemListController::hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
277 {
278 // The implementation assumes that only one item can get hovered no matter
279 // whether they overlap or not.
280
281 Q_UNUSED(transform);
282 if (!m_model || !m_view) {
283 return false;
284 }
285
286 // Search the previously hovered item that might get unhovered
287 KItemListWidget* unhoveredWidget = 0;
288 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
289 if (widget->isHovered()) {
290 unhoveredWidget = widget;
291 break;
292 }
293 }
294
295 // Search the currently hovered item
296 KItemListWidget* hoveredWidget = 0;
297 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
298 const QPointF mappedPos = widget->mapFromItem(m_view, event->pos());
299
300 const bool hovered = widget->contains(mappedPos) &&
301 !widget->expansionToggleRect().contains(mappedPos) &&
302 !widget->selectionToggleRect().contains(mappedPos);
303 if (hovered) {
304 hoveredWidget = widget;
305 break;
306 }
307 }
308
309 if (unhoveredWidget != hoveredWidget) {
310 if (unhoveredWidget) {
311 unhoveredWidget->setHovered(false);
312 emit itemUnhovered(unhoveredWidget->index());
313 }
314
315 if (hoveredWidget) {
316 hoveredWidget->setHovered(true);
317 emit itemHovered(hoveredWidget->index());
318 }
319 }
320
321 return false;
322 }
323
324 bool KItemListController::hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform)
325 {
326 Q_UNUSED(event);
327 Q_UNUSED(transform);
328
329 if (!m_model || !m_view) {
330 return false;
331 }
332
333 foreach (KItemListWidget* widget, m_view->visibleItemListWidgets()) {
334 if (widget->isHovered()) {
335 widget->setHovered(false);
336 emit itemUnhovered(widget->index());
337 }
338 }
339 return false;
340 }
341
342 bool KItemListController::wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform)
343 {
344 Q_UNUSED(event);
345 Q_UNUSED(transform);
346 return false;
347 }
348
349 bool KItemListController::resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform)
350 {
351 Q_UNUSED(event);
352 Q_UNUSED(transform);
353 return false;
354 }
355
356 bool KItemListController::processEvent(QEvent* event, const QTransform& transform)
357 {
358 if (!event) {
359 return false;
360 }
361
362 switch (event->type()) {
363 case QEvent::KeyPress:
364 return keyPressEvent(static_cast<QKeyEvent*>(event));
365 case QEvent::InputMethod:
366 return inputMethodEvent(static_cast<QInputMethodEvent*>(event));
367 case QEvent::GraphicsSceneMousePress:
368 return mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
369 case QEvent::GraphicsSceneMouseMove:
370 return mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
371 case QEvent::GraphicsSceneMouseRelease:
372 return mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event), QTransform());
373 case QEvent::GraphicsSceneWheel:
374 return wheelEvent(static_cast<QGraphicsSceneWheelEvent*>(event), QTransform());
375 case QEvent::GraphicsSceneDragEnter:
376 return dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
377 case QEvent::GraphicsSceneDragLeave:
378 return dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
379 case QEvent::GraphicsSceneDragMove:
380 return dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
381 case QEvent::GraphicsSceneDrop:
382 return dropEvent(static_cast<QGraphicsSceneDragDropEvent*>(event), QTransform());
383 case QEvent::GraphicsSceneHoverEnter:
384 return hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
385 case QEvent::GraphicsSceneHoverMove:
386 return hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
387 case QEvent::GraphicsSceneHoverLeave:
388 return hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent*>(event), QTransform());
389 case QEvent::GraphicsSceneResize:
390 return resizeEvent(static_cast<QGraphicsSceneResizeEvent*>(event), transform);
391 default:
392 break;
393 }
394
395 return false;
396 }
397
398 #include "kitemlistcontroller.moc"