• Skip to content
  • Skip to link menu
KDE 4.0 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KFile

kurlnavigatorbutton.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at>                      *
00003  * Copyright (C) 2006 by Aaron J. Seigo <aseigo@kde.org>                     *
00004  *                                                                           *
00005  * This library is free software; you can redistribute it and/or             *
00006  * modify it under the terms of the GNU Library General Public               *
00007  * License version 2 as published by the Free Software Foundation.           *
00008  *                                                                           *
00009  * This library is distributed in the hope that it will be useful,           *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00012  * Library General Public License for more details.                          *
00013  *                                                                           *
00014  * You should have received a copy of the GNU Library General Public License *
00015  * along with this library; see the file COPYING.LIB.  If not, write to      *
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00017  * Boston, MA 02110-1301, USA.                                               *
00018  *****************************************************************************/
00019 
00020 #include "kurlnavigatorbutton_p.h"
00021 
00022 #include <assert.h>
00023 
00024 #include "kurlnavigator.h"
00025 #include "kdirsortfilterproxymodel.h"
00026 
00027 #include <kio/job.h>
00028 #include <kio/jobclasses.h>
00029 #include <kglobalsettings.h>
00030 #include <kmenu.h>
00031 
00032 #include <QtCore/QTimer>
00033 #include <QtGui/QPainter>
00034 #include <QtGui/QKeyEvent>
00035 #include <QtGui/QStyleOption>
00036 
00037 KUrlNavigatorButton::KUrlNavigatorButton(int index, KUrlNavigator* parent) :
00038     KUrlButton(parent),
00039     m_index(-1),
00040     m_hoverArrow(false),
00041     m_popupPosition(0, 0),
00042     m_popupDelay(0),
00043     m_listJob(0)
00044 {
00045     setAcceptDrops(true);
00046     setIndex(index);
00047     setMouseTracking(true);
00048     connect(this, SIGNAL(clicked()), this, SLOT(updateNavigatorUrl()));
00049 
00050     m_popupDelay = new QTimer(this);
00051     m_popupDelay->setSingleShot(true);
00052     connect(m_popupDelay, SIGNAL(timeout()), this, SLOT(startListJob()));
00053     connect(this, SIGNAL(pressed()), this, SLOT(startPopupDelay()));
00054 }
00055 
00056 KUrlNavigatorButton::~KUrlNavigatorButton()
00057 {
00058 }
00059 
00060 void KUrlNavigatorButton::setIndex(int index)
00061 {
00062     m_index = index;
00063 
00064     if (m_index < 0) {
00065         return;
00066     }
00067 
00068     QString path(urlNavigator()->url().pathOrUrl());
00069     const QString buttonText = path.section('/', index, index);
00070     setText(buttonText);
00071 
00072     // Check whether the button indicates the full path of the URL. If
00073     // this is the case, the button is marked as 'active'.
00074     ++index;
00075     QFont adjustedFont(font());
00076     if (path.section('/', index, index).isEmpty()) {
00077         setDisplayHintEnabled(ActivatedHint, true);
00078         adjustedFont.setBold(true);
00079     } else {
00080         setDisplayHintEnabled(ActivatedHint, false);
00081         adjustedFont.setBold(false);
00082     }
00083 
00084     setFont(adjustedFont);
00085     updateMinimumWidth();
00086     update();
00087 }
00088 
00089 QSize KUrlNavigatorButton::sizeHint() const
00090 {
00091     // the minimum size is textWidth + arrowWidth() + 2 * BorderWidth; for the
00092     // preferred size we add the BorderWidth 2 times again for having an uncluttered look
00093     int width = fontMetrics().width(text()) + arrowWidth() + 4 * BorderWidth;
00094     if (width < minimumWidth()) {
00095         width = minimumWidth();
00096     }
00097     return QSize(width, KUrlButton::sizeHint().height());
00098 }
00099 
00100 void KUrlNavigatorButton::updateMinimumWidth()
00101 {
00102     QFontMetrics fontMetrics(font());
00103     int minWidth = fontMetrics.width(text()) + arrowWidth() + 2 * BorderWidth;
00104     if (minWidth < 50) {
00105         minWidth = 50;
00106     }
00107     else if (minWidth > 150) {
00108         // don't let an overlong path name waste all the URL navigator space
00109         minWidth = 150;
00110     }
00111     setMinimumWidth(minWidth);
00112 }
00113 
00114 void KUrlNavigatorButton::paintEvent(QPaintEvent* event)
00115 {
00116     QPainter painter(this);
00117     painter.setClipRect(event->rect());
00118     const int buttonWidth  = width();
00119     const int buttonHeight = height();
00120 
00121     const QColor bgColor = backgroundColor();
00122     const QColor fgColor = foregroundColor();
00123 
00124     // draw button background
00125     if (bgColor != Qt::transparent)
00126         painter.fillRect(rect(), bgColor);
00127 
00128     int textLeft = 0;
00129     int textWidth = buttonWidth;
00130 
00131     const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
00132 
00133     if (!isDisplayHintEnabled(ActivatedHint)) {
00134         // draw arrow
00135         const int arrowSize = arrowWidth();
00136         const int arrowX = leftToRight ? (buttonWidth - arrowSize) - BorderWidth : BorderWidth;
00137         const int arrowY = (buttonHeight - arrowSize) / 2;
00138 
00139         QStyleOption option;
00140         option.initFrom(this);
00141         option.rect = QRect(arrowX, arrowY, arrowSize, arrowSize);
00142         option.palette = palette();
00143         option.palette.setColor(QPalette::Text, fgColor);
00144         option.palette.setColor(QPalette::WindowText, fgColor);
00145         option.palette.setColor(QPalette::ButtonText, fgColor);
00146 
00147         if (m_hoverArrow) {
00148             // highlight the background of the arrow to indicate that the directories
00149             // popup can be opened by a mouse click
00150             QColor hoverColor = fgColor;
00151             hoverColor.setAlpha(96);
00152             painter.setPen(Qt::NoPen);
00153             painter.setBrush(hoverColor);
00154 
00155             int hoverX = arrowX;
00156             if (!leftToRight) {
00157                 hoverX -= BorderWidth;
00158             }
00159             painter.drawRect(QRect(hoverX, 0, arrowSize + BorderWidth, buttonHeight));
00160         }
00161 
00162         if (leftToRight) {
00163             style()->drawPrimitive(QStyle::PE_IndicatorArrowRight, &option, &painter, this);
00164         } else {
00165             style()->drawPrimitive(QStyle::PE_IndicatorArrowLeft, &option, &painter, this);
00166             textLeft += arrowSize + 2 * BorderWidth;
00167         }
00168 
00169         textWidth -= arrowSize + 2 * BorderWidth;
00170     }
00171 
00172     painter.setPen(fgColor);
00173     const bool clipped = isTextClipped();
00174     const int align = clipped ? Qt::AlignVCenter : Qt::AlignCenter;
00175     const QRect textRect(textLeft, 0, textWidth, buttonHeight);
00176     if (clipped) {
00177         QLinearGradient gradient(textRect.topLeft(), textRect.topRight());
00178         if (leftToRight) {
00179             gradient.setColorAt(0.8, fgColor);
00180             gradient.setColorAt(1.0, bgColor);
00181         } else {
00182             gradient.setColorAt(0.0, bgColor);
00183             gradient.setColorAt(0.2, fgColor);
00184         }
00185 
00186         QPen pen;
00187         pen.setBrush(QBrush(gradient));
00188         painter.setPen(pen);
00189     }
00190     painter.drawText(textRect, align, text());
00191 }
00192 
00193 void KUrlNavigatorButton::enterEvent(QEvent* event)
00194 {
00195     KUrlButton::enterEvent(event);
00196 
00197     // if the text is clipped due to a small window width, the text should
00198     // be shown as tooltip
00199     if (isTextClipped()) {
00200         setToolTip(text());
00201     }
00202 }
00203 
00204 void KUrlNavigatorButton::leaveEvent(QEvent* event)
00205 {
00206     KUrlButton::leaveEvent(event);
00207     setToolTip(QString());
00208 
00209     if (m_hoverArrow) {
00210         m_hoverArrow = false;
00211         update();
00212     }
00213 }
00214 
00215 void KUrlNavigatorButton::dropEvent(QDropEvent* event)
00216 {
00217     if (m_index < 0) {
00218         return;
00219     }
00220 
00221     const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00222     if (!urls.isEmpty()) {
00223         event->acceptProposedAction();
00224 
00225         setDisplayHintEnabled(DraggedHint, true);
00226 
00227         QString path(urlNavigator()->url().prettyUrl());
00228         path = path.section('/', 0, m_index + 2);
00229 
00230         emit urlsDropped(urls, KUrl(path));
00231 
00232         setDisplayHintEnabled(DraggedHint, false);
00233         update();
00234     }
00235 }
00236 
00237 void KUrlNavigatorButton::dragEnterEvent(QDragEnterEvent* event)
00238 {
00239     if (event->mimeData()->hasUrls()) {
00240         setDisplayHintEnabled(DraggedHint, true);
00241         event->acceptProposedAction();
00242 
00243         update();
00244     }
00245 }
00246 
00247 void KUrlNavigatorButton::dragLeaveEvent(QDragLeaveEvent* event)
00248 {
00249     KUrlButton::dragLeaveEvent(event);
00250 
00251     setDisplayHintEnabled(DraggedHint, false);
00252     update();
00253 }
00254 
00255 void KUrlNavigatorButton::mousePressEvent(QMouseEvent* event)
00256 {
00257     if (isAboveArrow(event->x()) && (event->button() == Qt::LeftButton)) {
00258         // the mouse is pressed above the arrow, hence show all directories
00259         const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
00260         const int popupX = leftToRight ? width() - arrowWidth() - BorderWidth : 0;
00261         m_popupPosition = urlNavigator()->mapToGlobal(geometry().bottomLeft() + QPoint(popupX, 0));
00262         startListJob();
00263     } else {
00264         // the mouse is pressed above the text area
00265         KUrlButton::mousePressEvent(event);
00266     }
00267 }
00268 
00269 void KUrlNavigatorButton::mouseReleaseEvent(QMouseEvent* event)
00270 {
00271     if (!isAboveArrow(event->x()) || (event->button() != Qt::LeftButton)) {
00272         // the mouse is released above the text area
00273         KUrlButton::mouseReleaseEvent(event);
00274     }
00275 }
00276 
00277 void KUrlNavigatorButton::mouseMoveEvent(QMouseEvent* event)
00278 {
00279     KUrlButton::mouseMoveEvent(event);
00280 
00281     const bool hoverArrow = isAboveArrow(event->x());
00282     if (hoverArrow != m_hoverArrow) {
00283         m_hoverArrow = hoverArrow;
00284         update();
00285     }
00286 }
00287 
00288 void KUrlNavigatorButton::updateNavigatorUrl()
00289 {
00290     stopPopupDelay();
00291 
00292     if (m_index < 0) {
00293         return;
00294     }
00295 
00296     urlNavigator()->setUrl(urlNavigator()->url(m_index));
00297 }
00298 
00299 void KUrlNavigatorButton::startPopupDelay()
00300 {
00301     if (m_popupDelay->isActive() || (m_listJob != 0) || (m_index < 0)) {
00302         return;
00303     }
00304 
00305     m_popupPosition = urlNavigator()->mapToGlobal(geometry().bottomLeft());
00306     m_popupDelay->start(300);
00307 }
00308 
00309 void KUrlNavigatorButton::stopPopupDelay()
00310 {
00311     m_popupDelay->stop();
00312     if (m_listJob != 0) {
00313         m_listJob->kill();
00314         m_listJob = 0;
00315     }
00316 }
00317 
00318 void KUrlNavigatorButton::startListJob()
00319 {
00320     if (m_listJob != 0) {
00321         return;
00322     }
00323 
00324     const KUrl& url = urlNavigator()->url(m_index);
00325     m_listJob = KIO::listDir(url, KIO::HideProgressInfo, false /*no hidden files*/);
00326     m_subdirs.clear(); // just to be ++safe
00327 
00328     connect(m_listJob, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList &)),
00329             this, SLOT(entriesList(KIO::Job*, const KIO::UDSEntryList&)));
00330     connect(m_listJob, SIGNAL(result(KJob*)), this, SLOT(listJobFinished(KJob*)));
00331 }
00332 
00333 void KUrlNavigatorButton::entriesList(KIO::Job* job, const KIO::UDSEntryList& entries)
00334 {
00335     if (job != m_listJob) {
00336         return;
00337     }
00338 
00339     KIO::UDSEntryList::const_iterator it = entries.constBegin();
00340     const KIO::UDSEntryList::const_iterator itEnd = entries.constEnd();
00341 
00342     while (it != itEnd) {
00343         const KIO::UDSEntry entry = *it;
00344         if (entry.isDir()) {
00345             const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
00346             if ((name != ".") && (name != "..")) {
00347                 m_subdirs.append(name);
00348             }
00349         }
00350 
00351         ++it;
00352     }
00353 }
00354 
00358 static bool naturalLessThan(const QString& s1, const QString& s2)
00359 {
00360     return KDirSortFilterProxyModel::naturalCompare(s1.toLower(), s2.toLower()) < 0;
00361 }
00362 
00363 void KUrlNavigatorButton::listJobFinished(KJob* job)
00364 {
00365     if (job != m_listJob) {
00366         return;
00367     }
00368 
00369     m_listJob = 0;
00370     if (job->error() || m_subdirs.isEmpty()) {
00371         // clear listing
00372         return;
00373     }
00374 
00375     qSort(m_subdirs.begin(), m_subdirs.end(), naturalLessThan);
00376     setDisplayHintEnabled(PopupActiveHint, true);
00377     update(); // ensure the button is drawn highlighted
00378 
00379     KMenu* dirsMenu = new KMenu(this);
00380     QStringList::const_iterator it = m_subdirs.constBegin();
00381     QStringList::const_iterator itEnd = m_subdirs.constEnd();
00382     int i = 0;
00383     while (it != itEnd) {
00384         QAction* action = new QAction(*it, this);
00385         action->setData(i);
00386         dirsMenu->addAction(action);
00387         ++it;
00388         ++i;
00389     }
00390 
00391     const QAction* action = dirsMenu->exec(m_popupPosition);
00392     if (action != 0) {
00393         const int result = action->data().toInt();
00394         KUrl url = urlNavigator()->url(m_index);
00395         url.addPath(m_subdirs[result]);
00396         urlNavigator()->setUrl(url);
00397     }
00398 
00399     m_subdirs.clear();
00400     delete dirsMenu;
00401     dirsMenu = 0;
00402 
00403     setDisplayHintEnabled(PopupActiveHint, false);
00404 }
00405 
00406 int KUrlNavigatorButton::arrowWidth() const
00407 {
00408     // if there isn't arrow then return 0
00409     int width = 0;
00410     if (!isDisplayHintEnabled(ActivatedHint)) {
00411         width = height() / 2;
00412         if (width < 4) {
00413             width = 4;
00414         }
00415     }
00416 
00417     return width;
00418 }
00419 
00420 bool KUrlNavigatorButton::isAboveArrow(int x) const
00421 {
00422     const bool leftToRight = (layoutDirection() == Qt::LeftToRight);
00423     return leftToRight ? (x >= width() - arrowWidth()) : (x < arrowWidth());
00424 }
00425 
00426 bool KUrlNavigatorButton::isTextClipped() const
00427 {
00428     int availableWidth = width() - 2 * BorderWidth;
00429     if (!isDisplayHintEnabled(ActivatedHint)) {
00430         availableWidth -= arrowWidth() - BorderWidth;
00431     }
00432 
00433     QFontMetrics fontMetrics(font());
00434     return fontMetrics.width(text()) >= availableWidth;
00435 }
00436 
00437 #include "kurlnavigatorbutton_p.moc"

KFile

Skip menu "KFile"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal