1 /***************************************************************************
2 * Copyright (C) 2008 by Peter Penz <peter.penz19@gmail.com> *
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. *
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. *
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 ***************************************************************************/
20 #include "selectionmanager.h"
22 #include "dolphinmodel.h"
23 #include "dolphin_generalsettings.h"
24 #include "selectiontoggle.h"
25 #include "settings/dolphinsettings.h"
27 #include <KGlobalSettings>
28 #include <KIconEffect>
30 #include <QAbstractButton>
31 #include <QAbstractItemView>
32 #include <QAbstractProxyModel>
33 #include <QApplication>
34 #include <QModelIndex>
36 #include <QPaintEvent>
40 SelectionManager::SelectionManager(QAbstractItemView
* parent
) :
45 m_appliedPointingHandCursor(false)
47 connect(parent
, SIGNAL(entered(const QModelIndex
&)),
48 this, SLOT(slotEntered(const QModelIndex
&)));
49 connect(parent
, SIGNAL(viewportEntered()),
50 this, SLOT(slotViewportEntered()));
52 const GeneralSettings
* settings
= DolphinSettings::instance().generalSettings();
53 if (settings
->showSelectionToggle()) {
54 m_toggle
= new SelectionToggle(m_view
->viewport());
55 m_toggle
->setCheckable(true);
57 connect(m_toggle
, SIGNAL(clicked(bool)),
58 this, SLOT(setItemSelected(bool)));
59 m_toggle
->installEventFilter(this);
62 m_view
->viewport()->installEventFilter(this);
65 SelectionManager::~SelectionManager()
69 bool SelectionManager::eventFilter(QObject
* watched
, QEvent
* event
)
71 if (watched
== m_view
->viewport()) {
72 switch (event
->type()) {
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.
85 const QRect
toggleBounds(m_toggle
->mapToGlobal(QPoint(0, 0)), m_toggle
->size());
86 m_toggle
->setVisible(toggleBounds
.contains(QCursor::pos()));
94 } else if (watched
== m_toggle
) {
95 switch (event
->type()) {
97 QApplication::changeOverrideCursor(Qt::ArrowCursor
);
101 QApplication::changeOverrideCursor(Qt::PointingHandCursor
);
109 return QObject::eventFilter(watched
, event
);
112 void SelectionManager::reset()
119 void SelectionManager::slotEntered(const QModelIndex
& index
)
121 const bool isSelectionCandidate
= index
.isValid() &&
122 (index
.column() == DolphinModel::Name
) &&
123 (QApplication::mouseButtons() == Qt::NoButton
);
126 if (isSelectionCandidate
&& KGlobalSettings::singleClick()) {
127 applyPointingHandCursor();
130 if (isSelectionCandidate
) {
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
&)),
137 SLOT(slotSelectionChanged(const QItemSelection
&, const QItemSelection
&)));
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
&)),
146 SLOT(slotSelectionChanged(const QItemSelection
&, const QItemSelection
&)));
155 if (isSelectionCandidate
) {
156 m_toggle
->setUrl(urlForIndex(index
));
158 // Increase the size of the toggle for large items
159 const int iconHeight
= m_view
->iconSize().height();
161 int toggleSize
= KIconLoader::SizeSmall
;
162 if (iconHeight
>= KIconLoader::SizeEnormous
) {
163 toggleSize
= KIconLoader::SizeMedium
;
164 } else if (iconHeight
>= KIconLoader::SizeLarge
) {
165 toggleSize
= KIconLoader::SizeSmallMedium
;
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;
175 toggleSize
+= 2 * margin
;
176 m_toggle
->setMargin(margin
);
177 m_toggle
->resize(toggleSize
, toggleSize
);
178 m_toggle
->move(rect
.topLeft());
180 QItemSelectionModel
* selModel
= m_view
->selectionModel();
181 m_toggle
->setChecked(selModel
->isSelected(index
));
184 m_toggle
->setUrl(KUrl());
188 void SelectionManager::slotViewportEntered()
196 void SelectionManager::setItemSelected(bool selected
)
198 emit
selectionChanged();
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();
205 selModel
->select(index
, QItemSelectionModel::Select
);
207 selModel
->select(index
, QItemSelectionModel::Deselect
);
209 selModel
->setCurrentIndex(index
, QItemSelectionModel::Current
);
214 void SelectionManager::slotRowsRemoved(const QModelIndex
& parent
, int start
, int end
)
225 void SelectionManager::slotSelectionChanged(const QItemSelection
& selected
,
226 const QItemSelection
& deselected
)
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);
238 if (deselected
.contains(index
)) {
239 m_toggle
->setChecked(false);
245 KUrl
SelectionManager::urlForIndex(const QModelIndex
& index
) const
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();
253 const QModelIndex
SelectionManager::indexForUrl(const KUrl
& url
) const
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
);
262 void SelectionManager::applyPointingHandCursor()
264 if (!m_appliedPointingHandCursor
) {
265 QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor
));
266 m_appliedPointingHandCursor
= true;
270 void SelectionManager::restoreCursor()
272 if (m_appliedPointingHandCursor
) {
273 QApplication::restoreOverrideCursor();
274 m_appliedPointingHandCursor
= false;
278 #include "selectionmanager.moc"