]> cloud.milkyroute.net Git - dolphin.git/blob - src/urlnavigatorbutton.cpp
Use a KIO Job for applying the view properties recursively to sub directories.
[dolphin.git] / src / urlnavigatorbutton.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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 #include "urlnavigatorbutton.h"
22 #include <qcursor.h>
23 #include <qfontmetrics.h>
24 #include <qpainter.h>
25 #include <qtimer.h>
26 #include <qtooltip.h>
27 //Added by qt3to4:
28 #include <QDropEvent>
29 #include <QDragLeaveEvent>
30 #include <Q3PopupMenu>
31 #include <QEvent>
32 #include <QDragEnterEvent>
33
34 #include <kglobalsettings.h>
35 #include <kiconloader.h>
36 #include <kio/jobclasses.h>
37 #include <klocale.h>
38 #include <kurl.h>
39 #include <assert.h>
40
41 #include "urlnavigator.h"
42 #include "dolphinview.h"
43 #include "dolphinmainwindow.h"
44
45 UrlNavigatorButton::UrlNavigatorButton(int index, UrlNavigator* parent) :
46 UrlButton(parent),
47 m_index(-1),
48 m_listJob(0)
49 {
50 setAcceptDrops(true);
51 setMinimumWidth(arrowWidth());
52 setIndex(index);
53 connect(this, SIGNAL(clicked()), this, SLOT(updateNavigatorUrl()));
54
55 m_popupDelay = new QTimer(this);
56 connect(m_popupDelay, SIGNAL(timeout()), this, SLOT(startListJob()));
57 connect(this, SIGNAL(pressed()), this, SLOT(startPopupDelay()));
58 }
59
60 UrlNavigatorButton::~UrlNavigatorButton()
61 {
62 }
63
64 void UrlNavigatorButton::setIndex(int index)
65 {
66 m_index = index;
67
68 if (m_index < 0) {
69 return;
70 }
71
72 QString path(urlNavigator()->url().pathOrUrl());
73 setText(path.section('/', index, index));
74
75 // Check whether the button indicates the full path of the Url. If
76 // this is the case, the button is marked as 'active'.
77 ++index;
78 QFont adjustedFont(font());
79 if (path.section('/', index, index).isEmpty()) {
80 setDisplayHintEnabled(ActivatedHint, true);
81 adjustedFont.setBold(true);
82 }
83 else {
84 setDisplayHintEnabled(ActivatedHint, false);
85 adjustedFont.setBold(false);
86 }
87
88 setFont(adjustedFont);
89 update();
90 }
91
92 QSize UrlNavigatorButton::sizeHint() const
93 {
94 const int width = fontMetrics().width(text()) + (arrowWidth() * 4);
95 return QSize(width, UrlButton::sizeHint().height());
96 }
97
98 void UrlNavigatorButton::paintEvent(QPaintEvent* event)
99 {
100 QPainter painter(this);
101 painter.setClipRect(event->rect());
102 const int buttonWidth = width();
103 const int buttonHeight = height();
104
105 QColor backgroundColor;
106 QColor foregroundColor;
107 const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
108 isDisplayHintEnabled(DraggedHint) ||
109 isDisplayHintEnabled(PopupActiveHint);
110 if (isHighlighted) {
111 backgroundColor = KGlobalSettings::highlightColor();
112 foregroundColor = KGlobalSettings::highlightedTextColor();
113 }
114 else {
115 backgroundColor = palette().brush(QPalette::Background).color();
116 foregroundColor = KGlobalSettings::buttonTextColor();
117 }
118
119 // dimm the colors if the parent view does not have the focus
120 const DolphinView* parentView = urlNavigator()->dolphinView();
121 const DolphinMainWindow* dolphin = parentView->mainWindow();
122
123 const bool isActive = (dolphin->activeView() == parentView);
124 if (!isActive) {
125 QColor dimmColor(palette().brush(QPalette::Background).color());
126 foregroundColor = mixColors(foregroundColor, dimmColor);
127 if (isHighlighted) {
128 backgroundColor = mixColors(backgroundColor, dimmColor);
129 }
130 }
131
132 // draw button background
133 painter.setPen(Qt::NoPen);
134 painter.setBrush(backgroundColor);
135 painter.drawRect(0, 0, buttonWidth, buttonHeight);
136
137 int textWidth = buttonWidth;
138 if (isDisplayHintEnabled(ActivatedHint) && isActive || isHighlighted) {
139 painter.setPen(foregroundColor);
140 }
141 else {
142 // dimm the foreground color by mixing it with the background
143 foregroundColor = mixColors(foregroundColor, backgroundColor);
144 painter.setPen(foregroundColor);
145 }
146
147 if (!isDisplayHintEnabled(ActivatedHint)) {
148 // draw arrow
149 const int border = 2; // horizontal border
150 const int middleY = height() / 2;
151 const int width = arrowWidth();
152 const int startX = (buttonWidth - width) - (2 * border);
153 const int startTopY = middleY - (width - 1);
154 const int startBottomY = middleY + (width - 1);
155 for (int i = 0; i < width; ++i) {
156 painter.drawLine(startX, startTopY + i, startX + i, startTopY + i);
157 painter.drawLine(startX, startBottomY - i, startX + i, startBottomY - i);
158 }
159
160 textWidth = startX - border;
161 }
162
163 const bool clipped = isTextClipped();
164 const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
165 painter.drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
166
167 if (clipped) {
168 // Blend the right area of the text with the background, as the
169 // text is clipped.
170 // TODO: use alpha blending in Qt4 instead of drawing the text that often
171 const int blendSteps = 16;
172
173 QColor blendColor(backgroundColor);
174 const int redInc = (foregroundColor.red() - backgroundColor.red()) / blendSteps;
175 const int greenInc = (foregroundColor.green() - backgroundColor.green()) / blendSteps;
176 const int blueInc = (foregroundColor.blue() - backgroundColor.blue()) / blendSteps;
177 for (int i = 0; i < blendSteps; ++i) {
178 painter.setClipRect(QRect(textWidth - i, 0, 1, buttonHeight));
179 painter.setPen(blendColor);
180 painter.drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
181
182 blendColor.setRgb(blendColor.red() + redInc,
183 blendColor.green() + greenInc,
184 blendColor.blue() + blueInc);
185 }
186 }
187 }
188
189 void UrlNavigatorButton::enterEvent(QEvent* event)
190 {
191 UrlButton::enterEvent(event);
192
193 // if the text is clipped due to a small window width, the text should
194 // be shown as tooltip
195 if (isTextClipped()) {
196 setToolTip(text());
197 }
198 }
199
200 void UrlNavigatorButton::leaveEvent(QEvent* event)
201 {
202 UrlButton::leaveEvent(event);
203 setToolTip(QString());
204 }
205
206 void UrlNavigatorButton::dropEvent(QDropEvent* event)
207 {
208 if (m_index < 0) {
209 return;
210 }
211
212 KUrl::List urls;
213 /* KDE4-TODO:
214 if (KUrlDrag::decode(event, urls) && !urls.isEmpty()) {
215 setDisplayHintEnabled(DraggedHint, true);
216
217 QString path(urlNavigator()->url().prettyUrl());
218 path = path.section('/', 0, m_index);
219
220 Dolphin::mainWin().dropUrls(urls, KUrl(path));
221
222 setDisplayHintEnabled(DraggedHint, false);
223 update();
224 }*/
225 }
226
227 void UrlNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
228 {
229 /* KDE4-TODO:
230 event->accept(KUrlDrag::canDecode(event));
231
232 setDisplayHintEnabled(DraggedHint, true);*/
233 update();
234 }
235
236 void UrlNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
237 {
238 UrlButton::dragLeaveEvent(event);
239
240 setDisplayHintEnabled(DraggedHint, false);
241 update();
242 }
243
244
245 void UrlNavigatorButton::updateNavigatorUrl()
246 {
247 if (m_index < 0) {
248 return;
249 }
250
251 UrlNavigator* navigator = urlNavigator();
252 assert(navigator != 0);
253 navigator->setUrl(navigator->url(m_index));
254 }
255
256 void UrlNavigatorButton::startPopupDelay()
257 {
258 if (m_popupDelay->isActive() || m_listJob || m_index < 0) {
259 return;
260 }
261
262 m_popupDelay->setSingleShot(true);
263 m_popupDelay->start(300);
264 }
265
266 void UrlNavigatorButton::stopPopupDelay()
267 {
268 m_popupDelay->stop();
269 if (m_listJob) {
270 m_listJob->kill();
271 m_listJob = 0;
272 }
273 }
274
275 void UrlNavigatorButton::startListJob()
276 {
277 if (m_listJob) {
278 return;
279 }
280
281 KUrl url = urlNavigator()->url(m_index);
282 m_listJob = KIO::listDir(url, false, false);
283 m_subdirs.clear(); // just to be ++safe
284
285 connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
286 this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
287 connect(m_listJob, SIGNAL(result(KJob*)), this, SLOT(listJobFinished(KJob*)));
288 }
289
290 void UrlNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
291 {
292 if (job != m_listJob) {
293 return;
294 }
295
296 KIO::UDSEntryList::const_iterator it = entries.constBegin();
297 KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
298 while (it != itEnd) {
299 QString name;
300 bool isDir = false;
301 KIO::UDSEntry entry = *it;
302
303 /* KDE3 reference:
304 KIO::UDSEntry::const_iterator atomIt = entry.constBegin();
305 KIO::UDSEntry::const_iterator atomEndIt = entry.constEnd();
306
307 while (atomIt != atomEndIt) {
308 switch ((*atomIt).m_uds) {
309 case KIO::UDS_NAME:
310 name = (*atomIt).m_str;
311 break;
312 case KIO::UDS_FILE_TYPE:
313 isDir = S_ISDIR((*atomIt).m_long);
314 break;
315 default:
316 break;
317 }
318 ++atomIt;
319 }
320 if (isDir) {
321 m_subdirs.append(name);
322 }
323 */
324
325 if (entry.isDir()) {
326 m_subdirs.append(entry.stringValue(KIO::UDS_NAME));
327 }
328
329 ++it;
330 }
331
332 m_subdirs.sort();
333 }
334
335 void UrlNavigatorButton::listJobFinished(KJob* job)
336 {
337 if (job != m_listJob) {
338 return;
339 }
340
341 if (job->error() || m_subdirs.isEmpty()) {
342 // clear listing
343 return;
344 }
345
346 setDisplayHintEnabled(PopupActiveHint, true);
347 update(); // ensure the button is drawn highlighted
348 Q3PopupMenu* dirsMenu = new Q3PopupMenu(this);
349 //setPopup(dirsMenu);
350 QStringList::const_iterator it = m_subdirs.constBegin();
351 QStringList::const_iterator itEnd = m_subdirs.constEnd();
352 int i = 0;
353 while (it != itEnd) {
354 dirsMenu->insertItem(*it, i);
355 ++it;
356 ++i;
357 }
358
359 int result = dirsMenu->exec(urlNavigator()->mapToGlobal(geometry().bottomLeft()));
360
361 if (result != -1) {
362 KUrl url = urlNavigator()->url(m_index);
363 url.addPath(m_subdirs[result]);
364 urlNavigator()->setUrl(url);
365 }
366
367 m_listJob = 0;
368 m_subdirs.clear();
369 delete dirsMenu;
370 setDisplayHintEnabled(PopupActiveHint, false);
371 }
372
373 int UrlNavigatorButton::arrowWidth() const
374 {
375 int width = (height() / 2) - 7;
376 if (width < 4) {
377 width = 4;
378 }
379 return width;
380 }
381
382 bool UrlNavigatorButton::isTextClipped() const
383 {
384 int availableWidth = width();
385 if (!isDisplayHintEnabled(ActivatedHint)) {
386 availableWidth -= arrowWidth() + 1;
387 }
388
389 QFontMetrics fontMetrics(font());
390 return fontMetrics.width(text()) >= availableWidth;
391 }
392
393 #include "urlnavigatorbutton.moc"