]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/selectionmanager.cpp
9c0dd8bda24da68ec1bce8026c896d80e348a617
[dolphin.git] / src / views / selectionmanager.cpp
1 /***************************************************************************
2 * Copyright (C) 2008 by Peter Penz <peter.penz@gmx.at> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "selectionmanager.h"
21
22 #include "dolphinmodel.h"
23 #include "selectiontoggle.h"
24 #include <kdirmodel.h>
25 #include <kglobalsettings.h>
26 #include <kiconeffect.h>
27
28 #include <QAbstractButton>
29 #include <QAbstractItemView>
30 #include <QAbstractProxyModel>
31 #include <QApplication>
32 #include <QModelIndex>
33 #include <QPainter>
34 #include <QPaintEvent>
35 #include <QRect>
36 #include <QTimeLine>
37
38 SelectionManager::SelectionManager(QAbstractItemView* parent) :
39 QObject(parent),
40 m_view(parent),
41 m_toggle(0),
42 m_connected(false),
43 m_appliedPointingHandCursor(false)
44 {
45 connect(parent, SIGNAL(entered(const QModelIndex&)),
46 this, SLOT(slotEntered(const QModelIndex&)));
47 connect(parent, SIGNAL(viewportEntered()),
48 this, SLOT(slotViewportEntered()));
49 m_toggle = new SelectionToggle(m_view->viewport());
50 m_toggle->setCheckable(true);
51 m_toggle->hide();
52 connect(m_toggle, SIGNAL(clicked(bool)),
53 this, SLOT(setItemSelected(bool)));
54 m_toggle->installEventFilter(this);
55
56 m_view->viewport()->installEventFilter(this);
57 }
58
59 SelectionManager::~SelectionManager()
60 {
61 }
62
63 bool SelectionManager::eventFilter(QObject* watched, QEvent* event)
64 {
65 if (watched == m_view->viewport()) {
66 switch (event->type()) {
67 case QEvent::Leave:
68 m_toggle->hide();
69 break;
70
71 case QEvent::MouseButtonPress: {
72 // Set the toggle invisible, if a mouse button has been pressed
73 // outside the toggle boundaries. This e.g. assures, that the toggle
74 // gets invisible during dragging items.
75 const QRect toggleBounds(m_toggle->mapToGlobal(QPoint(0, 0)), m_toggle->size());
76 m_toggle->setVisible(toggleBounds.contains(QCursor::pos()));
77 break;
78 }
79
80 default:
81 break;
82 }
83 } else if (watched == m_toggle) {
84 switch (event->type()) {
85 case QEvent::Hide:
86 // If the toggle button gets hidden, the cursor is not above the item
87 // anymore and the shape must get restored
88 restoreCursor();
89 break;
90
91 case QEvent::Enter:
92 QApplication::changeOverrideCursor(Qt::ArrowCursor);
93 break;
94
95 case QEvent::Leave:
96 QApplication::changeOverrideCursor(Qt::PointingHandCursor);
97 break;
98
99 default:
100 break;
101 }
102 }
103
104 return QObject::eventFilter(watched, event);
105 }
106
107 void SelectionManager::reset()
108 {
109 m_toggle->reset();
110 }
111
112 void SelectionManager::slotEntered(const QModelIndex& index)
113 {
114 m_toggle->hide();
115 const bool showToggle = index.isValid() &&
116 (index.column() == DolphinModel::Name) &&
117 (QApplication::mouseButtons() == Qt::NoButton);
118 if (showToggle) {
119 if (KGlobalSettings::singleClick()) {
120 applyPointingHandCursor();
121 }
122
123 m_toggle->setUrl(urlForIndex(index));
124
125 if (!m_connected) {
126 connect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
127 this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
128 connect(m_view->selectionModel(),
129 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
130 this,
131 SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
132 m_connected = true;
133 }
134
135 // Increase the size of the toggle for large items
136 const int iconHeight = m_view->iconSize().height();
137
138 int toggleSize = KIconLoader::SizeSmall;
139 if (iconHeight >= KIconLoader::SizeEnormous) {
140 toggleSize = KIconLoader::SizeMedium;
141 } else if (iconHeight >= KIconLoader::SizeLarge) {
142 toggleSize = KIconLoader::SizeSmallMedium;
143 }
144
145 // Add a small invisible margin, if the item-height is nearly
146 // equal to the toggleSize (#169494).
147 const QRect rect = m_view->visualRect(index);
148 int margin = (rect.height() - toggleSize) / 2;
149 if (margin > 4) {
150 margin = 0;
151 }
152 toggleSize += 2 * margin;
153 m_toggle->setMargin(margin);
154 m_toggle->resize(toggleSize, toggleSize);
155 m_toggle->move(rect.topLeft());
156
157 QItemSelectionModel* selModel = m_view->selectionModel();
158 m_toggle->setChecked(selModel->isSelected(index));
159 m_toggle->show();
160 } else {
161 m_toggle->setUrl(KUrl());
162 disconnect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
163 this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
164 disconnect(m_view->selectionModel(),
165 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
166 this,
167 SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
168 m_connected = false;
169 }
170 }
171
172 void SelectionManager::slotViewportEntered()
173 {
174 m_toggle->hide();
175 }
176
177 void SelectionManager::setItemSelected(bool selected)
178 {
179 emit selectionChanged();
180
181 if (!m_toggle->url().isEmpty()) {
182 const QModelIndex index = indexForUrl(m_toggle->url());
183 if (index.isValid()) {
184 QItemSelectionModel* selModel = m_view->selectionModel();
185 if (selected) {
186 selModel->select(index, QItemSelectionModel::Select);
187 } else {
188 selModel->select(index, QItemSelectionModel::Deselect);
189 }
190 selModel->setCurrentIndex(index, QItemSelectionModel::Current);
191 }
192 }
193 }
194
195 void SelectionManager::slotRowsRemoved(const QModelIndex& parent, int start, int end)
196 {
197 Q_UNUSED(parent);
198 Q_UNUSED(start);
199 Q_UNUSED(end);
200 m_toggle->hide();
201 }
202
203 void SelectionManager::slotSelectionChanged(const QItemSelection& selected,
204 const QItemSelection& deselected)
205 {
206 // The selection has been changed outside the scope of the selection manager
207 // (e. g. by the rubberband or the "Select All" action). Take care updating
208 // the state of the toggle button.
209 if (!m_toggle->url().isEmpty()) {
210 const QModelIndex index = indexForUrl(m_toggle->url());
211 if (index.isValid()) {
212 if (selected.contains(index)) {
213 m_toggle->setChecked(true);
214 }
215
216 if (deselected.contains(index)) {
217 m_toggle->setChecked(false);
218 }
219 }
220 }
221 }
222
223 KUrl SelectionManager::urlForIndex(const QModelIndex& index) const
224 {
225 QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
226 KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
227 const QModelIndex dirIndex = proxyModel->mapToSource(index);
228 return dirModel->itemForIndex(dirIndex).url();
229 }
230
231 const QModelIndex SelectionManager::indexForUrl(const KUrl& url) const
232 {
233 QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
234 KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
235 const QModelIndex dirIndex = dirModel->indexForUrl(url);
236 return proxyModel->mapFromSource(dirIndex);
237 }
238
239
240 void SelectionManager::applyPointingHandCursor()
241 {
242 if (!m_appliedPointingHandCursor) {
243 QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
244 m_appliedPointingHandCursor = true;
245 }
246 }
247
248 void SelectionManager::restoreCursor()
249 {
250 if (m_appliedPointingHandCursor) {
251 QApplication::restoreOverrideCursor();
252 m_appliedPointingHandCursor = false;
253 }
254 }
255
256 #include "selectionmanager.moc"