]> cloud.milkyroute.net Git - dolphin.git/blob - src/urlnavigatorbutton.cpp
Let's remove the connect errors because of the KJob/KIO::Job split.
[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 "dolphin.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 const int buttonWidth = width();
102 const int buttonHeight = height();
103
104 QColor backgroundColor;
105 QColor foregroundColor;
106 const bool isHighlighted = isDisplayHintEnabled(EnteredHint) ||
107 isDisplayHintEnabled(DraggedHint) ||
108 isDisplayHintEnabled(PopupActiveHint);
109 if (isHighlighted) {
110 backgroundColor = KGlobalSettings::highlightColor();
111 foregroundColor = KGlobalSettings::highlightedTextColor();
112 }
113 else {
114 backgroundColor = colorGroup().background();
115 foregroundColor = KGlobalSettings::buttonTextColor();
116 }
117
118 // dimm the colors if the parent view does not have the focus
119 const DolphinView* parentView = urlNavigator()->dolphinView();
120 const Dolphin& dolphin = Dolphin::mainWin();
121
122 const bool isActive = (dolphin.activeView() == parentView);
123 if (!isActive) {
124 QColor dimmColor(colorGroup().background());
125 foregroundColor = mixColors(foregroundColor, dimmColor);
126 if (isHighlighted) {
127 backgroundColor = mixColors(backgroundColor, dimmColor);
128 }
129 }
130
131 // draw button background
132 painter.setPen(Qt::NoPen);
133 painter.setBrush(backgroundColor);
134 painter.drawRect(0, 0, buttonWidth, buttonHeight);
135
136 int textWidth = buttonWidth;
137 if (isDisplayHintEnabled(ActivatedHint) && isActive || isHighlighted) {
138 painter.setPen(foregroundColor);
139 }
140 else {
141 // dimm the foreground color by mixing it with the background
142 foregroundColor = mixColors(foregroundColor, backgroundColor);
143 painter.setPen(foregroundColor);
144 }
145
146 if (!isDisplayHintEnabled(ActivatedHint)) {
147 // draw arrow
148 const int border = 2; // horizontal border
149 const int middleY = height() / 2;
150 const int width = arrowWidth();
151 const int startX = (buttonWidth - width) - (2 * border);
152 const int startTopY = middleY - (width - 1);
153 const int startBottomY = middleY + (width - 1);
154 for (int i = 0; i < width; ++i) {
155 painter.drawLine(startX, startTopY + i, startX + i, startTopY + i);
156 painter.drawLine(startX, startBottomY - i, startX + i, startBottomY - i);
157 }
158
159 textWidth = startX - border;
160 }
161
162 const bool clipped = isTextClipped();
163 const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
164 painter.drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
165
166 if (clipped) {
167 // Blend the right area of the text with the background, as the
168 // text is clipped.
169 // TODO: use alpha blending in Qt4 instead of drawing the text that often
170 const int blendSteps = 16;
171
172 QColor blendColor(backgroundColor);
173 const int redInc = (foregroundColor.red() - backgroundColor.red()) / blendSteps;
174 const int greenInc = (foregroundColor.green() - backgroundColor.green()) / blendSteps;
175 const int blueInc = (foregroundColor.blue() - backgroundColor.blue()) / blendSteps;
176 for (int i = 0; i < blendSteps; ++i) {
177 painter.setClipRect(QRect(textWidth - i, 0, 1, buttonHeight));
178 painter.setPen(blendColor);
179 painter.drawText(QRect(0, 0, textWidth, buttonHeight), align, text());
180
181 blendColor.setRgb(blendColor.red() + redInc,
182 blendColor.green() + greenInc,
183 blendColor.blue() + blueInc);
184 }
185 }
186 }
187
188 void UrlNavigatorButton::enterEvent(QEvent* event)
189 {
190 UrlButton::enterEvent(event);
191
192 // if the text is clipped due to a small window width, the text should
193 // be shown as tooltip
194 if (isTextClipped()) {
195 QToolTip::add(this, text());
196 }
197 }
198
199 void UrlNavigatorButton::leaveEvent(QEvent* event)
200 {
201 UrlButton::leaveEvent(event);
202 QToolTip::remove(this);
203 }
204
205 void UrlNavigatorButton::dropEvent(QDropEvent* event)
206 {
207 if (m_index < 0) {
208 return;
209 }
210
211 KUrl::List urls;
212 /* KDE4-TODO:
213 if (KUrlDrag::decode(event, urls) && !urls.isEmpty()) {
214 setDisplayHintEnabled(DraggedHint, true);
215
216 QString path(urlNavigator()->url().prettyUrl());
217 path = path.section('/', 0, m_index);
218
219 Dolphin::mainWin().dropUrls(urls, KUrl(path));
220
221 setDisplayHintEnabled(DraggedHint, false);
222 update();
223 }*/
224 }
225
226 void UrlNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
227 {
228 /* KDE4-TODO:
229 event->accept(KUrlDrag::canDecode(event));
230
231 setDisplayHintEnabled(DraggedHint, true);*/
232 update();
233 }
234
235 void UrlNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
236 {
237 UrlButton::dragLeaveEvent(event);
238
239 setDisplayHintEnabled(DraggedHint, false);
240 update();
241 }
242
243
244 void UrlNavigatorButton::updateNavigatorUrl()
245 {
246 if (m_index < 0) {
247 return;
248 }
249
250 UrlNavigator* navigator = urlNavigator();
251 assert(navigator != 0);
252 navigator->setUrl(navigator->url(m_index));
253 }
254
255 void UrlNavigatorButton::startPopupDelay()
256 {
257 if (m_popupDelay->isActive() || m_listJob || m_index < 0) {
258 return;
259 }
260
261 m_popupDelay->start(300, true);
262 }
263
264 void UrlNavigatorButton::stopPopupDelay()
265 {
266 m_popupDelay->stop();
267 if (m_listJob) {
268 m_listJob->kill();
269 m_listJob = 0;
270 }
271 }
272
273 void UrlNavigatorButton::startListJob()
274 {
275 if (m_listJob) {
276 return;
277 }
278
279 KUrl url = urlNavigator()->url(m_index);
280 m_listJob = KIO::listDir(url, false, false);
281 m_subdirs.clear(); // just to be ++safe
282
283 connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
284 this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
285 connect(m_listJob, SIGNAL(result(KJob*)), this, SLOT(listJobFinished(KJob*)));
286 }
287
288 void UrlNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
289 {
290 if (job != m_listJob) {
291 return;
292 }
293
294 KIO::UDSEntryList::const_iterator it = entries.constBegin();
295 KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
296 while (it != itEnd) {
297 QString name;
298 bool isDir = false;
299 KIO::UDSEntry entry = *it;
300
301 /* KDE3 reference:
302 KIO::UDSEntry::const_iterator atomIt = entry.constBegin();
303 KIO::UDSEntry::const_iterator atomEndIt = entry.constEnd();
304
305 while (atomIt != atomEndIt) {
306 switch ((*atomIt).m_uds) {
307 case KIO::UDS_NAME:
308 name = (*atomIt).m_str;
309 break;
310 case KIO::UDS_FILE_TYPE:
311 isDir = S_ISDIR((*atomIt).m_long);
312 break;
313 default:
314 break;
315 }
316 ++atomIt;
317 }
318 if (isDir) {
319 m_subdirs.append(name);
320 }
321 */
322
323 if (entry.isDir()) {
324 m_subdirs.append(entry.stringValue(KIO::UDS_NAME));
325 }
326
327 ++it;
328 }
329
330 m_subdirs.sort();
331 }
332
333 void UrlNavigatorButton::listJobFinished(KJob* job)
334 {
335 if (job != m_listJob) {
336 return;
337 }
338
339 if (job->error() || m_subdirs.isEmpty()) {
340 // clear listing
341 return;
342 }
343
344 setDisplayHintEnabled(PopupActiveHint, true);
345 update(); // ensure the button is drawn highlighted
346 Q3PopupMenu* dirsMenu = new Q3PopupMenu(this);
347 //setPopup(dirsMenu);
348 QStringList::const_iterator it = m_subdirs.constBegin();
349 QStringList::const_iterator itEnd = m_subdirs.constEnd();
350 int i = 0;
351 while (it != itEnd) {
352 dirsMenu->insertItem(*it, i);
353 ++i;
354 ++it;
355 }
356
357 int result = dirsMenu->exec(urlNavigator()->mapToGlobal(geometry().bottomLeft()));
358
359 if (result != -1) {
360 KUrl url = urlNavigator()->url(m_index);
361 url.addPath(m_subdirs[result]);
362 urlNavigator()->setUrl(url);
363 }
364
365 m_listJob = 0;
366 m_subdirs.clear();
367 delete dirsMenu;
368 setDisplayHintEnabled(PopupActiveHint, false);
369 }
370
371 int UrlNavigatorButton::arrowWidth() const
372 {
373 int width = (height() / 2) - 7;
374 if (width < 4) {
375 width = 4;
376 }
377 return width;
378 }
379
380 bool UrlNavigatorButton::isTextClipped() const
381 {
382 int availableWidth = width();
383 if (!isDisplayHintEnabled(ActivatedHint)) {
384 availableWidth -= arrowWidth() + 1;
385 }
386
387 QFontMetrics fontMetrics(font());
388 return fontMetrics.width(text()) >= availableWidth;
389 }
390
391 #include "urlnavigatorbutton.moc"