1 /***************************************************************************
2 * Copyright (C) 2008 by Peter Penz <peter.penz@gmx.at> *
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 "selectiontoggle.h"
24 #include <kdirmodel.h>
25 #include <kiconeffect.h>
27 #include <QAbstractButton>
28 #include <QAbstractItemView>
29 #include <QAbstractProxyModel>
30 #include <QApplication>
31 #include <QModelIndex>
33 #include <QPaintEvent>
37 SelectionManager::SelectionManager(QAbstractItemView
* parent
) :
42 m_appliedPointingHandCursor(false)
44 connect(parent
, SIGNAL(entered(const QModelIndex
&)),
45 this, SLOT(slotEntered(const QModelIndex
&)));
46 connect(parent
, SIGNAL(viewportEntered()),
47 this, SLOT(slotViewportEntered()));
48 m_toggle
= new SelectionToggle(m_view
->viewport());
49 m_toggle
->setCheckable(true);
51 connect(m_toggle
, SIGNAL(clicked(bool)),
52 this, SLOT(setItemSelected(bool)));
53 m_toggle
->installEventFilter(this);
55 m_view
->viewport()->installEventFilter(this);
58 SelectionManager::~SelectionManager()
62 bool SelectionManager::eventFilter(QObject
* watched
, QEvent
* event
)
64 if (watched
== m_view
->viewport()) {
65 switch (event
->type()) {
70 case QEvent::MouseButtonPress
: {
71 // Set the toggle invisible, if a mouse button has been pressed
72 // outside the toggle boundaries. This e.g. assures, that the toggle
73 // gets invisible during dragging items.
74 const QRect
toggleBounds(m_toggle
->mapToGlobal(QPoint(0, 0)), m_toggle
->size());
75 m_toggle
->setVisible(toggleBounds
.contains(QCursor::pos()));
82 } else if (watched
== m_toggle
) {
83 switch (event
->type()) {
85 // If the toggle button gets hidden, the cursor is not above the item
86 // anymore and the shape must get restored
91 QApplication::changeOverrideCursor(Qt::ArrowCursor
);
95 QApplication::changeOverrideCursor(Qt::PointingHandCursor
);
103 return QObject::eventFilter(watched
, event
);
106 void SelectionManager::reset()
111 void SelectionManager::slotEntered(const QModelIndex
& index
)
114 const bool showToggle
= index
.isValid() &&
115 (index
.column() == DolphinModel::Name
) &&
116 (QApplication::mouseButtons() == Qt::NoButton
);
118 applyPointingHandCursor();
120 m_toggle
->setUrl(urlForIndex(index
));
123 connect(m_view
->model(), SIGNAL(rowsRemoved(const QModelIndex
&, int, int)),
124 this, SLOT(slotRowsRemoved(const QModelIndex
&, int, int)));
125 connect(m_view
->selectionModel(),
126 SIGNAL(selectionChanged(const QItemSelection
&, const QItemSelection
&)),
128 SLOT(slotSelectionChanged(const QItemSelection
&, const QItemSelection
&)));
132 // Increase the size of the toggle for large items
133 const int iconHeight
= m_view
->iconSize().height();
135 int toggleSize
= KIconLoader::SizeSmall
;
136 if (iconHeight
>= KIconLoader::SizeEnormous
) {
137 toggleSize
= KIconLoader::SizeMedium
;
138 } else if (iconHeight
>= KIconLoader::SizeLarge
) {
139 toggleSize
= KIconLoader::SizeSmallMedium
;
142 // Add a small invisible margin, if the item-height is nearly
143 // equal to the toggleSize (#169494).
144 const QRect rect
= m_view
->visualRect(index
);
145 int margin
= (rect
.height() - toggleSize
) / 2;
149 toggleSize
+= 2 * margin
;
150 m_toggle
->setMargin(margin
);
151 m_toggle
->resize(toggleSize
, toggleSize
);
152 m_toggle
->move(rect
.topLeft());
154 QItemSelectionModel
* selModel
= m_view
->selectionModel();
155 m_toggle
->setChecked(selModel
->isSelected(index
));
158 m_toggle
->setUrl(KUrl());
159 disconnect(m_view
->model(), SIGNAL(rowsRemoved(const QModelIndex
&, int, int)),
160 this, SLOT(slotRowsRemoved(const QModelIndex
&, int, int)));
161 disconnect(m_view
->selectionModel(),
162 SIGNAL(selectionChanged(const QItemSelection
&, const QItemSelection
&)),
164 SLOT(slotSelectionChanged(const QItemSelection
&, const QItemSelection
&)));
169 void SelectionManager::slotViewportEntered()
174 void SelectionManager::setItemSelected(bool selected
)
176 emit
selectionChanged();
178 if (!m_toggle
->url().isEmpty()) {
179 const QModelIndex index
= indexForUrl(m_toggle
->url());
180 if (index
.isValid()) {
181 QItemSelectionModel
* selModel
= m_view
->selectionModel();
183 selModel
->select(index
, QItemSelectionModel::Select
);
185 selModel
->select(index
, QItemSelectionModel::Deselect
);
187 selModel
->setCurrentIndex(index
, QItemSelectionModel::Current
);
192 void SelectionManager::slotRowsRemoved(const QModelIndex
& parent
, int start
, int end
)
200 void SelectionManager::slotSelectionChanged(const QItemSelection
& selected
,
201 const QItemSelection
& deselected
)
203 // The selection has been changed outside the scope of the selection manager
204 // (e. g. by the rubberband or the "Select All" action). Take care updating
205 // the state of the toggle button.
206 if (!m_toggle
->url().isEmpty()) {
207 const QModelIndex index
= indexForUrl(m_toggle
->url());
208 if (index
.isValid()) {
209 if (selected
.contains(index
)) {
210 m_toggle
->setChecked(true);
213 if (deselected
.contains(index
)) {
214 m_toggle
->setChecked(false);
220 KUrl
SelectionManager::urlForIndex(const QModelIndex
& index
) const
222 QAbstractProxyModel
* proxyModel
= static_cast<QAbstractProxyModel
*>(m_view
->model());
223 KDirModel
* dirModel
= static_cast<KDirModel
*>(proxyModel
->sourceModel());
224 const QModelIndex dirIndex
= proxyModel
->mapToSource(index
);
225 return dirModel
->itemForIndex(dirIndex
).url();
228 const QModelIndex
SelectionManager::indexForUrl(const KUrl
& url
) const
230 QAbstractProxyModel
* proxyModel
= static_cast<QAbstractProxyModel
*>(m_view
->model());
231 KDirModel
* dirModel
= static_cast<KDirModel
*>(proxyModel
->sourceModel());
232 const QModelIndex dirIndex
= dirModel
->indexForUrl(url
);
233 return proxyModel
->mapFromSource(dirIndex
);
237 void SelectionManager::applyPointingHandCursor()
239 if (!m_appliedPointingHandCursor
) {
240 QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor
));
241 m_appliedPointingHandCursor
= true;
245 void SelectionManager::restoreCursor()
247 if (m_appliedPointingHandCursor
) {
248 QApplication::restoreOverrideCursor();
249 m_appliedPointingHandCursor
= false;
253 #include "selectionmanager.moc"