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