]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/selectionmanager.cpp
7a9e814126c998bc1400d2c3d1003ab1cda819e8
[dolphin.git] / src / views / selectionmanager.cpp
1 /***************************************************************************
2 * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
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 "dolphin_generalsettings.h"
24 #include "selectiontoggle.h"
25 #include "settings/dolphinsettings.h"
26 #include <KDirModel>
27 #include <KGlobalSettings>
28 #include <KIconEffect>
29
30 #include <QAbstractButton>
31 #include <QAbstractItemView>
32 #include <QAbstractProxyModel>
33 #include <QApplication>
34 #include <QModelIndex>
35 #include <QPainter>
36 #include <QPaintEvent>
37 #include <QRect>
38 #include <QTimeLine>
39
40 SelectionManager::SelectionManager(QAbstractItemView* parent) :
41 QObject(parent),
42 m_view(parent),
43 m_toggle(0),
44 m_connected(false),
45 m_appliedPointingHandCursor(false)
46 {
47 connect(parent, SIGNAL(entered(const QModelIndex&)),
48 this, SLOT(slotEntered(const QModelIndex&)));
49 connect(parent, SIGNAL(viewportEntered()),
50 this, SLOT(slotViewportEntered()));
51
52 const GeneralSettings* settings = DolphinSettings::instance().generalSettings();
53 if (settings->showSelectionToggle()) {
54 m_toggle = new SelectionToggle(m_view->viewport());
55 m_toggle->setCheckable(true);
56 m_toggle->hide();
57 connect(m_toggle, SIGNAL(clicked(bool)),
58 this, SLOT(setItemSelected(bool)));
59 m_toggle->installEventFilter(this);
60 }
61
62 m_view->viewport()->installEventFilter(this);
63 }
64
65 SelectionManager::~SelectionManager()
66 {
67 }
68
69 bool SelectionManager::eventFilter(QObject* watched, QEvent* event)
70 {
71 if (watched == m_view->viewport()) {
72 switch (event->type()) {
73 case QEvent::Leave:
74 if (m_toggle) {
75 m_toggle->hide();
76 }
77 restoreCursor();
78 break;
79
80 case QEvent::MouseButtonPress: {
81 // Set the toggle invisible, if a mouse button has been pressed
82 // outside the toggle boundaries. This e.g. assures, that the toggle
83 // gets invisible during dragging items.
84 if (m_toggle) {
85 const QRect toggleBounds(m_toggle->mapToGlobal(QPoint(0, 0)), m_toggle->size());
86 m_toggle->setVisible(toggleBounds.contains(QCursor::pos()));
87 }
88 break;
89 }
90
91 default:
92 break;
93 }
94 } else if (watched == m_toggle) {
95 switch (event->type()) {
96 case QEvent::Enter:
97 QApplication::changeOverrideCursor(Qt::ArrowCursor);
98 break;
99
100 case QEvent::Leave:
101 QApplication::changeOverrideCursor(Qt::PointingHandCursor);
102 break;
103
104 default:
105 break;
106 }
107 }
108
109 return QObject::eventFilter(watched, event);
110 }
111
112 void SelectionManager::reset()
113 {
114 if (m_toggle) {
115 m_toggle->reset();
116 }
117 }
118
119 void SelectionManager::slotEntered(const QModelIndex& index)
120 {
121 const bool isSelectionCandidate = index.isValid() &&
122 (index.column() == DolphinModel::Name) &&
123 (QApplication::mouseButtons() == Qt::NoButton);
124
125 restoreCursor();
126 if (isSelectionCandidate && KGlobalSettings::singleClick()) {
127 applyPointingHandCursor();
128 }
129
130 if (isSelectionCandidate) {
131 if (!m_connected) {
132 connect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
133 this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
134 connect(m_view->selectionModel(),
135 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
136 this,
137 SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
138 m_connected = true;
139 }
140 } else {
141 disconnect(m_view->model(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
142 this, SLOT(slotRowsRemoved(const QModelIndex&, int, int)));
143 disconnect(m_view->selectionModel(),
144 SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
145 this,
146 SLOT(slotSelectionChanged(const QItemSelection&, const QItemSelection&)));
147 m_connected = false;
148 }
149
150 if (!m_toggle) {
151 return;
152 }
153
154 m_toggle->hide();
155 if (isSelectionCandidate) {
156 m_toggle->setUrl(urlForIndex(index));
157
158 // Increase the size of the toggle for large items
159 const int iconHeight = m_view->iconSize().height();
160
161 int toggleSize = KIconLoader::SizeSmall;
162 if (iconHeight >= KIconLoader::SizeEnormous) {
163 toggleSize = KIconLoader::SizeMedium;
164 } else if (iconHeight >= KIconLoader::SizeLarge) {
165 toggleSize = KIconLoader::SizeSmallMedium;
166 }
167
168 // Add a small invisible margin, if the item-height is nearly
169 // equal to the toggleSize (#169494).
170 const QRect rect = m_view->visualRect(index);
171 int margin = (rect.height() - toggleSize) / 2;
172 if (margin > 4) {
173 margin = 0;
174 }
175 toggleSize += 2 * margin;
176 m_toggle->setMargin(margin);
177 m_toggle->resize(toggleSize, toggleSize);
178 m_toggle->move(rect.topLeft());
179
180 QItemSelectionModel* selModel = m_view->selectionModel();
181 m_toggle->setChecked(selModel->isSelected(index));
182 m_toggle->show();
183 } else {
184 m_toggle->setUrl(KUrl());
185 }
186 }
187
188 void SelectionManager::slotViewportEntered()
189 {
190 if (m_toggle) {
191 m_toggle->hide();
192 }
193 restoreCursor();
194 }
195
196 void SelectionManager::setItemSelected(bool selected)
197 {
198 emit selectionChanged();
199
200 if (m_toggle && !m_toggle->url().isEmpty()) {
201 const QModelIndex index = indexForUrl(m_toggle->url());
202 if (index.isValid()) {
203 QItemSelectionModel* selModel = m_view->selectionModel();
204 if (selected) {
205 selModel->select(index, QItemSelectionModel::Select);
206 } else {
207 selModel->select(index, QItemSelectionModel::Deselect);
208 }
209 selModel->setCurrentIndex(index, QItemSelectionModel::Current);
210 }
211 }
212 }
213
214 void SelectionManager::slotRowsRemoved(const QModelIndex& parent, int start, int end)
215 {
216 Q_UNUSED(parent);
217 Q_UNUSED(start);
218 Q_UNUSED(end);
219 if (m_toggle) {
220 m_toggle->hide();
221 }
222 restoreCursor();
223 }
224
225 void SelectionManager::slotSelectionChanged(const QItemSelection& selected,
226 const QItemSelection& deselected)
227 {
228 // The selection has been changed outside the scope of the selection manager
229 // (e. g. by the rubberband or the "Select All" action). Take care updating
230 // the state of the toggle button.
231 if (m_toggle && !m_toggle->url().isEmpty()) {
232 const QModelIndex index = indexForUrl(m_toggle->url());
233 if (index.isValid()) {
234 if (selected.contains(index)) {
235 m_toggle->setChecked(true);
236 }
237
238 if (deselected.contains(index)) {
239 m_toggle->setChecked(false);
240 }
241 }
242 }
243 }
244
245 KUrl SelectionManager::urlForIndex(const QModelIndex& index) const
246 {
247 QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
248 KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
249 const QModelIndex dirIndex = proxyModel->mapToSource(index);
250 return dirModel->itemForIndex(dirIndex).url();
251 }
252
253 const QModelIndex SelectionManager::indexForUrl(const KUrl& url) const
254 {
255 QAbstractProxyModel* proxyModel = static_cast<QAbstractProxyModel*>(m_view->model());
256 KDirModel* dirModel = static_cast<KDirModel*>(proxyModel->sourceModel());
257 const QModelIndex dirIndex = dirModel->indexForUrl(url);
258 return proxyModel->mapFromSource(dirIndex);
259 }
260
261
262 void SelectionManager::applyPointingHandCursor()
263 {
264 if (!m_appliedPointingHandCursor) {
265 QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
266 m_appliedPointingHandCursor = true;
267 }
268 }
269
270 void SelectionManager::restoreCursor()
271 {
272 if (m_appliedPointingHandCursor) {
273 QApplication::restoreOverrideCursor();
274 m_appliedPointingHandCursor = false;
275 }
276 }
277
278 #include "selectionmanager.moc"