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