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

KFile

Skip menu "KFile"
  • Main Page
  • Namespace List
  • 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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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