]> cloud.milkyroute.net Git - dolphin.git/blob - src/kurlnavigatorbutton.cpp
No need to call rowCount() all the time.
[dolphin.git] / src / kurlnavigatorbutton.cpp
1 /***************************************************************************
2 * Copyright (C) 2006 by Peter Penz (peter.penz@gmx.at) *
3 * Copyright (C) 2006 by Aaron J. Seigo (<aseigo@kde.org>) *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
19 ***************************************************************************/
20
21 #include "kurlnavigatorbutton_p.h"
22
23 #include <assert.h>
24
25 #include "kurlnavigator.h"
26
27 #include <kio/job.h>
28 #include <kio/jobclasses.h>
29 #include <kglobalsettings.h>
30 #include <kmenu.h>
31
32 #include <QPainter>
33 #include <QPaintEvent>
34 #include <QTimer>
35
36 KUrlNavigatorButton::KUrlNavigatorButton(int index, KUrlNavigator* parent) :
37 KUrlButton(parent),
38 m_index(-1),
39 m_popupDelay(0),
40 m_listJob(0)
41 {
42 setAcceptDrops(true);
43 setMinimumWidth(arrowWidth());
44 setIndex(index);
45 connect(this, SIGNAL(clicked()), this, SLOT(updateNavigatorUrl()));
46
47 m_popupDelay = new QTimer(this);
48 m_popupDelay->setSingleShot(true);
49 connect(m_popupDelay, SIGNAL(timeout()), this, SLOT(startListJob()));
50 connect(this, SIGNAL(pressed()), this, SLOT(startPopupDelay()));
51 }
52
53 KUrlNavigatorButton::~KUrlNavigatorButton()
54 {
55 }
56
57 void KUrlNavigatorButton::setIndex(int index)
58 {
59 m_index = index;
60
61 if (m_index < 0) {
62 return;
63 }
64
65 QString path(urlNavigator()->url().pathOrUrl());
66 setText(path.section('/', index, index));
67
68 // Check whether the button indicates the full path of the Url. If
69 // this is the case, the button is marked as 'active'.
70 ++index;
71 QFont adjustedFont(font());
72 if (path.section('/', index, index).isEmpty()) {
73 setDisplayHintEnabled(ActivatedHint, true);
74 adjustedFont.setBold(true);
75 }
76 else {
77 setDisplayHintEnabled(ActivatedHint, false);
78 adjustedFont.setBold(false);
79 }
80
81 setFont(adjustedFont);
82 update();
83 }
84
85 QSize KUrlNavigatorButton::sizeHint() const
86 {
87 const int width = fontMetrics().width(text()) + (arrowWidth() * 4);
88 return QSize(width, KUrlButton::sizeHint().height());
89 }
90
91 void KUrlNavigatorButton::paintEvent(QPaintEvent* event)
92 {
93 QPainter painter(this);
94 painter.setClipRect(event->rect());
95 const int buttonWidth = width();
96 const int buttonHeight = height();
97
98 QColor backgroundColor;
99 QColor foregroundColor;
100 const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
101 isDisplayHintEnabled(DraggedHint) ||
102 isDisplayHintEnabled(PopupActiveHint);
103 if (isHighlighted) {
104 backgroundColor = KGlobalSettings::highlightColor();
105 foregroundColor = KGlobalSettings::highlightedTextColor();
106 }
107 else {
108 backgroundColor = palette().brush(QPalette::Background).color();
109 foregroundColor = KGlobalSettings::buttonTextColor();
110 }
111
112 // dimm the colors if the parent view does not have the focus
113 const bool isActive = urlNavigator()->isActive();
114 if (!isActive) {
115 QColor dimmColor(palette().brush(QPalette::Background).color());
116 foregroundColor = mixColors(foregroundColor, dimmColor);
117 if (isHighlighted) {
118 backgroundColor = mixColors(backgroundColor, dimmColor);
119 }
120 }
121
122 // draw button background
123 painter.setPen(Qt::NoPen);
124 painter.setBrush(backgroundColor);
125 painter.drawRect(0, 0, buttonWidth, buttonHeight);
126
127 int textWidth = buttonWidth;
128 if (isDisplayHintEnabled(ActivatedHint) && isActive || isHighlighted) {
129 painter.setPen(foregroundColor);
130 }
131 else {
132 // dimm the foreground color by mixing it with the background
133 foregroundColor = mixColors(foregroundColor, backgroundColor);
134 painter.setPen(foregroundColor);
135 }
136
137 if (!isDisplayHintEnabled(ActivatedHint)) {
138 // draw arrow
139 const int border = 2; // horizontal border
140 const int middleY = height() / 2;
141 const int width = arrowWidth();
142 const int startX = (buttonWidth - width) - (2 * border);
143 const int startTopY = middleY - (width - 1);
144 const int startBottomY = middleY + (width - 1);
145 for (int i = 0; i < width; ++i) {
146 painter.drawLine(startX, startTopY + i, startX + i, startTopY + i);
147 painter.drawLine(startX, startBottomY - i, startX + i, startBottomY - i);
148 }
149
150 textWidth = startX - border;
151 }
152
153 const bool clipped = isTextClipped();
154 const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
155 const QRect textRect(0, 0, textWidth, buttonHeight);
156 if (clipped) {
157 QLinearGradient gradient(textRect.topLeft(), textRect.topRight());
158 gradient.setColorAt(0.8, foregroundColor);
159 gradient.setColorAt(1.0, backgroundColor);
160
161 QPen pen;
162 pen.setBrush(QBrush(gradient));
163 painter.setPen(pen);
164 painter.drawText(textRect, align, text());
165 }
166 else {
167 painter.drawText(textRect, align, text());
168 }
169 }
170
171 void KUrlNavigatorButton::enterEvent(QEvent* event)
172 {
173 KUrlButton::enterEvent(event);
174
175 // if the text is clipped due to a small window width, the text should
176 // be shown as tooltip
177 if (isTextClipped()) {
178 setToolTip(text());
179 }
180 }
181
182 void KUrlNavigatorButton::leaveEvent(QEvent* event)
183 {
184 KUrlButton::leaveEvent(event);
185 setToolTip(QString());
186 }
187
188 void KUrlNavigatorButton::dropEvent(QDropEvent* event)
189 {
190 if (m_index < 0) {
191 return;
192 }
193
194 const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
195 if (!urls.isEmpty()) {
196 event->acceptProposedAction();
197
198 setDisplayHintEnabled(DraggedHint, true);
199
200 QString path(urlNavigator()->url().prettyUrl());
201 path = path.section('/', 0, m_index + 2);
202
203 urlNavigator()->dropUrls(urls, KUrl(path));
204
205 setDisplayHintEnabled(DraggedHint, false);
206 update();
207 }
208 }
209
210 void KUrlNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
211 {
212 if (event->mimeData()->hasUrls()) {
213 setDisplayHintEnabled(DraggedHint, true);
214 event->acceptProposedAction();
215
216 update();
217 }
218 }
219
220 void KUrlNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
221 {
222 KUrlButton::dragLeaveEvent(event);
223
224 setDisplayHintEnabled(DraggedHint, false);
225 update();
226 }
227
228
229 void KUrlNavigatorButton::updateNavigatorUrl()
230 {
231 stopPopupDelay();
232
233 if (m_index < 0) {
234 return;
235 }
236
237 urlNavigator()->setUrl(urlNavigator()->url(m_index));
238 }
239
240 void KUrlNavigatorButton::startPopupDelay()
241 {
242 if (m_popupDelay->isActive() || (m_listJob != 0) || (m_index < 0)) {
243 return;
244 }
245
246 m_popupDelay->start(300);
247 }
248
249 void KUrlNavigatorButton::stopPopupDelay()
250 {
251 m_popupDelay->stop();
252 if (m_listJob != 0) {
253 m_listJob->kill();
254 m_listJob = 0;
255 }
256 }
257
258 void KUrlNavigatorButton::startListJob()
259 {
260 if (m_listJob != 0) {
261 return;
262 }
263
264 const KUrl& url = urlNavigator()->url(m_index);
265 m_listJob = KIO::listDir(url, false, urlNavigator()->showHiddenFiles());
266 m_subdirs.clear(); // just to be ++safe
267
268 connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
269 this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
270 connect(m_listJob, SIGNAL(result(KJob*)), this, SLOT(listJobFinished(KJob*)));
271 }
272
273 void KUrlNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
274 {
275 if (job != m_listJob) {
276 return;
277 }
278
279 KIO::UDSEntryList::const_iterator it = entries.constBegin();
280 KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
281
282 bool showHidden = urlNavigator()->showHiddenFiles();
283 while (it != itEnd) {
284 const KIO::UDSEntry entry = *it;
285 if (entry.isDir()) {
286 QString name = entry.stringValue(KIO::UDS_NAME);
287
288 if (!showHidden || (name != "." && name != "..")) {
289 m_subdirs.append(name);
290 }
291 }
292
293 ++it;
294 }
295
296 m_subdirs.sort();
297 }
298
299 void KUrlNavigatorButton::listJobFinished(KJob* job)
300 {
301 if (job != m_listJob) {
302 return;
303 }
304
305 if (job->error() || m_subdirs.isEmpty()) {
306 // clear listing
307 return;
308 }
309
310 setDisplayHintEnabled(PopupActiveHint, true);
311 update(); // ensure the button is drawn highlighted
312
313 KMenu* dirsMenu = new KMenu(this);
314 QStringList::const_iterator it = m_subdirs.constBegin();
315 QStringList::const_iterator itEnd = m_subdirs.constEnd();
316 int i = 0;
317 while (it != itEnd) {
318 QAction* action = new QAction(*it, this);
319 action->setData(i);
320 dirsMenu->addAction(action);
321 ++it;
322 ++i;
323 }
324
325 const QAction* action = dirsMenu->exec(urlNavigator()->mapToGlobal(geometry().bottomLeft()));
326 if (action != 0) {
327 const int result = action->data().toInt();
328 KUrl url = urlNavigator()->url(m_index);
329 url.addPath(m_subdirs[result]);
330 urlNavigator()->setUrl(url);
331 }
332
333 m_listJob = 0;
334 m_subdirs.clear();
335 delete dirsMenu;
336 dirsMenu = 0;
337
338 setDisplayHintEnabled(PopupActiveHint, false);
339 }
340
341 int KUrlNavigatorButton::arrowWidth() const
342 {
343 int width = (height() / 2) - 7;
344 if (width < 4) {
345 width = 4;
346 }
347 return width;
348 }
349
350 bool KUrlNavigatorButton::isTextClipped() const
351 {
352 int availableWidth = width();
353 if (!isDisplayHintEnabled(ActivatedHint)) {
354 availableWidth -= arrowWidth() + 1;
355 }
356
357 QFontMetrics fontMetrics(font());
358 return fontMetrics.width(text()) >= availableWidth;
359 }
360
361 #include "kurlnavigatorbutton_p.moc"