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