1 /* This file is part of the KDE project
2 *
3 * Copyright (C) 2008 Peter Penz <peter.penz19@gmail.com>
4 * Copyright (C) 2011 Paul Mendez <paulestebanms@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "KoViewItemContextBar.h"
23
24 //Calligra headers
25 #include "KoContextBarButton.h"
26 #include <KoIcon.h>
27
28 // KF5
29 #include <klocalizedstring.h>
30
31 //Qt Headers
32 #include <QAbstractItemView>
33 #include <QModelIndex>
34 #include <QApplication>
35 #include <QHBoxLayout>
36 #include <QHoverEvent>
37
38 /** Space between the item outer rect and the context bar */
39 const int CONTEXTBAR_MARGIN = 4;
40 const int MIN_BUTTON_WIDTH = 24;
41
KoViewItemContextBar(QAbstractItemView * parent)42 KoViewItemContextBar::KoViewItemContextBar(QAbstractItemView *parent)
43 : QObject(parent)
44 , m_view(parent)
45 , m_enabled(true)
46 , m_showToggleButton(true)
47 {
48 connect(parent, SIGNAL(entered(QModelIndex)),
49 this, SLOT(slotEntered(QModelIndex)));
50 connect(parent, SIGNAL(viewportEntered()),
51 this, SLOT(slotViewportEntered()));
52
53 m_ContextBar = new QWidget(m_view->viewport());
54 m_ContextBar->hide();
55 m_ToggleSelectionButton = new KoContextBarButton(koIconName("list-add"));
56
57 m_Layout = new QHBoxLayout(m_ContextBar);
58 m_Layout->setMargin(2);
59 m_Layout->setSpacing(2);
60 m_Layout->addWidget(m_ToggleSelectionButton);
61
62 connect(m_ToggleSelectionButton, SIGNAL(clicked()),
63 this, SLOT(setItemSelected()));
64 // Hides context bar if item removed
65 connect(m_view->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
66 this, SLOT(slotRowsRemoved(QModelIndex,int,int)));
67
68 connect(m_view->model(), SIGNAL(modelReset()), this, SLOT(slotModelReset()));
69
70 m_ContextBar->installEventFilter(this);
71 m_view->viewport()->installEventFilter(this);
72 m_view->setMouseTracking(true);
73 }
74
eventFilter(QObject * watched,QEvent * event)75 bool KoViewItemContextBar::eventFilter(QObject *watched, QEvent *event)
76 {
77 if (watched == m_view->viewport()) {
78 switch (event->type()) {
79 case QEvent::Leave:
80 if (m_ContextBar->isVisible()) {
81 m_ContextBar->hide();
82 }
83 break;
84 default:
85 break;
86 }
87 }
88 return QObject::eventFilter(watched, event);
89 }
90
slotEntered(const QModelIndex & index)91 void KoViewItemContextBar::slotEntered(const QModelIndex &index)
92 {
93 const bool isSelectionCandidate = index.isValid() &&
94 (QApplication::mouseButtons() == Qt::NoButton);
95
96 if (!m_ContextBar || !m_enabled) {
97 return;
98 }
99
100 m_ContextBar->hide();
101 if (isSelectionCandidate) {
102 updateHoverUi(index);
103 }
104 else {
105 updateHoverUi(QModelIndex());
106 }
107 }
108
updateHoverUi(const QModelIndex & index)109 void KoViewItemContextBar::updateHoverUi(const QModelIndex &index)
110 {
111 QModelIndex oldIndex = m_IndexUnderCursor;
112 m_IndexUnderCursor = index;
113 m_view->update(oldIndex);
114
115 const bool isSelectionCandidate = index.isValid();
116
117 m_ContextBar->hide();
118 if (isSelectionCandidate) {
119 updateToggleSelectionButton();
120 const QRect rect = m_view->visualRect(m_IndexUnderCursor);
121 showContextBar(rect);
122 m_view->update(m_IndexUnderCursor);
123 } else {
124 m_ContextBar->hide();
125 }
126 }
127
showContextBar(const QRect & rect)128 void KoViewItemContextBar::showContextBar(const QRect &rect)
129 {
130 // Center bar in FullContextBar mode, left align in
131 // SelectionOnlyContextBar mode
132 const int posX = 0;
133 const int posY = CONTEXTBAR_MARGIN / 4;
134 int numButtons = 0;
135 m_ContextBar->move(rect.topLeft() + QPoint(posX, posY));
136 //Hide buttons if item is too small
137 int width = m_ToggleSelectionButton->width();
138 if (!m_showToggleButton) {
139 m_ToggleSelectionButton->setVisible(false);
140 width = qMin(m_contextBarButtons.at(0)->width(), MIN_BUTTON_WIDTH);
141 }
142 for (int i=m_contextBarButtons.size()-1; i>=0; --i) {
143 if ((rect.width() - 2 * CONTEXTBAR_MARGIN) > ((i + 1) * width)) {
144 m_contextBarButtons.at(i)->setVisible(true);
145 numButtons++;
146 continue;
147 }
148 m_contextBarButtons.at(i)->setVisible(false);
149 }
150 m_ContextBar->adjustSize();
151 if (numButtons > 0) {
152 const int centerX = (rect.width() - m_ContextBar->rect().width()) / 2;
153 m_ContextBar->move(rect.topLeft() + QPoint(centerX, posY));
154 }
155 m_ContextBar->show();
156 }
157
slotViewportEntered()158 void KoViewItemContextBar::slotViewportEntered()
159 {
160 m_ContextBar->hide();
161 }
162
setItemSelected()163 void KoViewItemContextBar::setItemSelected()
164 {
165 emit selectionChanged();
166
167 if (m_IndexUnderCursor.isValid()) {
168 QItemSelectionModel *selModel = m_view->selectionModel();
169 if (!selModel->isSelected(m_IndexUnderCursor)) {
170 selModel->select(m_IndexUnderCursor, QItemSelectionModel::Select);
171 }
172 else {
173 selModel->select(m_IndexUnderCursor, QItemSelectionModel::Deselect);
174 }
175 selModel->setCurrentIndex(m_IndexUnderCursor, QItemSelectionModel::Current);
176 }
177 updateHoverUi(m_IndexUnderCursor);
178 }
179
slotRowsRemoved(const QModelIndex & parent,int start,int end)180 void KoViewItemContextBar::slotRowsRemoved(const QModelIndex &parent, int start, int end)
181 {
182 Q_UNUSED(parent);
183 Q_UNUSED(start);
184 Q_UNUSED(end);
185 if (m_ContextBar) {
186 m_ContextBar->hide();
187 }
188 }
189
updateToggleSelectionButton()190 void KoViewItemContextBar::updateToggleSelectionButton()
191 {
192 const bool isHoveredIndexSelected = m_view->selectionModel()->isSelected(m_IndexUnderCursor);
193 const char *const iconName = (isHoveredIndexSelected ? koIconNameCStr("list-remove") : koIconNameCStr("list-add"));
194
195 m_ToggleSelectionButton->setIcon(QIcon::fromTheme(QLatin1String(iconName)));
196 m_ToggleSelectionButton->setToolTip(isHoveredIndexSelected ? i18n("deselect item") : i18n("select item"));
197 }
198
update()199 void KoViewItemContextBar::update()
200 {
201 // Check if the current index is still valid and then update the context bar
202 if (m_view->model()->index(currentIndex().row(), currentIndex().column(), currentIndex().parent()).isValid()) {
203 updateHoverUi(currentIndex());
204 }
205 else {
206 updateHoverUi(QModelIndex());
207 }
208 }
209
addContextButton(const QString & text,const QString & iconName)210 QToolButton * KoViewItemContextBar::addContextButton(const QString &text, const QString &iconName)
211 {
212 KoContextBarButton *newContexButton = new KoContextBarButton(iconName);
213 newContexButton->setToolTip(text);
214 m_Layout->addWidget(newContexButton);
215 m_contextBarButtons.append(newContexButton);
216 return newContexButton;
217 }
218
currentIndex()219 QModelIndex KoViewItemContextBar::currentIndex()
220 {
221 return m_IndexUnderCursor;
222 }
223
preferredWidth()224 int KoViewItemContextBar::preferredWidth()
225 {
226 return ((m_contextBarButtons.count()+1)*m_ToggleSelectionButton->sizeHint().width() + 2*CONTEXTBAR_MARGIN);
227 }
228
setShowSelectionToggleButton(bool enabled)229 void KoViewItemContextBar::setShowSelectionToggleButton(bool enabled)
230 {
231 m_showToggleButton = enabled;
232 }
233
reset()234 void KoViewItemContextBar::reset()
235 {
236 if (m_ContextBar) {
237 m_ContextBar->hide();
238 }
239 }
240
slotModelReset()241 void KoViewItemContextBar::slotModelReset()
242 {
243 // reset the model index so it does no longer point to suff no longer available.
244 m_IndexUnderCursor = QModelIndex();
245 }
246
enableContextBar()247 void KoViewItemContextBar::enableContextBar()
248 {
249 m_enabled = true;
250 }
251
disableContextBar()252 void KoViewItemContextBar::disableContextBar()
253 {
254 m_enabled = false;
255 }
256