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

KFile

kurlnavigator.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  * Copyright (C) 2007 by Kevin Ottens <ervin@kde.org>                        *
00005  * Copyright (C) 2007 by Urs Wolfer <uwolfer @ kde.org>                      *
00006  *                                                                           *
00007  * This library is free software; you can redistribute it and/or             *
00008  * modify it under the terms of the GNU Library General Public               *
00009  * License version 2 as published by the Free Software Foundation.           *
00010  *                                                                           *
00011  * This library is distributed in the hope that it will be useful,           *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00014  * Library General Public License for more details.                          *
00015  *                                                                           *
00016  * You should have received a copy of the GNU Library General Public License *
00017  * along with this library; see the file COPYING.LIB.  If not, write to      *
00018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00019  * Boston, MA 02110-1301, USA.                                               *
00020  *****************************************************************************/
00021 
00022 #include "kurlnavigator.h"
00023 
00024 #include "kfileplacesselector_p.h"
00025 #include "kprotocolcombo_p.h"
00026 #include "kurldropdownbutton_p.h"
00027 #include "kurlnavigatorbutton_p.h"
00028 #include "kurltogglebutton_p.h"
00029 
00030 #include <kfileitem.h>
00031 #include <kfileplacesmodel.h>
00032 #include <kglobalsettings.h>
00033 #include <kicon.h>
00034 #include <klineedit.h>
00035 #include <klocale.h>
00036 #include <kmenu.h>
00037 #include <kprotocolinfo.h>
00038 #include <kurlcombobox.h>
00039 #include <kurlcompletion.h>
00040 
00041 #include <QtCore/QDir>
00042 #include <QtCore/QLinkedList>
00043 #include <QtCore/QTimer>
00044 #include <QtGui/QApplication>
00045 #include <QtGui/QClipboard>
00046 #include <QtGui/QKeyEvent>
00047 #include <QtGui/QBoxLayout>
00048 #include <QtGui/QLabel>
00049 
00056 class HistoryElem
00057 {
00058 public:
00059     HistoryElem();
00060     HistoryElem(const KUrl& url);
00061     ~HistoryElem(); // non virtual
00062 
00063     const KUrl& url() const;
00064 
00065     void setRootUrl(const KUrl& url);
00066     const KUrl& rootUrl() const;
00067 
00068     void setContentsX(int x);
00069     int contentsX() const;
00070 
00071     void setContentsY(int y);
00072     int contentsY() const;
00073 
00074 private:
00075     KUrl m_url;
00076     KUrl m_rootUrl;
00077     int m_contentsX;
00078     int m_contentsY;
00079 };
00080 
00081 HistoryElem::HistoryElem() :
00082     m_url(),
00083     m_rootUrl(),
00084     m_contentsX(0),
00085     m_contentsY(0)
00086 {
00087 }
00088 
00089 HistoryElem::HistoryElem(const KUrl& url) :
00090     m_url(url),
00091     m_rootUrl(),
00092     m_contentsX(0),
00093     m_contentsY(0)
00094 {
00095 }
00096 
00097 HistoryElem::~HistoryElem()
00098 {
00099 }
00100 
00101 inline const KUrl& HistoryElem::url() const
00102 {
00103     return m_url;
00104 }
00105 
00106 inline void HistoryElem::setRootUrl(const KUrl& url)
00107 {
00108     m_rootUrl = url;
00109 }
00110 
00111 inline const KUrl& HistoryElem::rootUrl() const
00112 {
00113     return m_rootUrl;
00114 }
00115 
00116 inline void HistoryElem::setContentsX(int x)
00117 {
00118     m_contentsX = x;
00119 }
00120 
00121 inline int HistoryElem::contentsX() const
00122 {
00123     return m_contentsX;
00124 }
00125 
00126 inline void HistoryElem::setContentsY(int y)
00127 {
00128     m_contentsY = y;
00129 }
00130 
00131 inline int HistoryElem::contentsY() const
00132 {
00133     return m_contentsY;
00134 }
00135 
00143 class HostLineEdit : public KLineEdit
00144 {
00145 public:
00146     explicit HostLineEdit(const QString& text, KUrlNavigator* parent = 0);
00147     virtual ~HostLineEdit();
00148     virtual QSize sizeHint() const;
00149     inline void setOptimizeWidth(bool optimize);
00150 
00151 protected:
00152     virtual void mousePressEvent(QMouseEvent* event);
00153 
00154 private:
00155     bool m_optimizeWidth;
00156     KUrlNavigator* m_urlNavigator;
00157 };
00158 
00159 HostLineEdit::HostLineEdit(const QString& text, KUrlNavigator* parent) :
00160     KLineEdit(text, parent),
00161     m_optimizeWidth(true),
00162     m_urlNavigator(parent)
00163 {
00164 }
00165 
00166 HostLineEdit::~HostLineEdit()
00167 {
00168 }
00169 
00170 void HostLineEdit::setOptimizeWidth(bool optimize)
00171 {
00172     m_optimizeWidth = optimize;
00173     setClearButtonShown(!optimize);
00174 }
00175 
00176 QSize HostLineEdit::sizeHint() const
00177 {
00178     QSize size = KLineEdit::sizeHint();
00179 
00180     if (m_optimizeWidth) {
00181         const QFontMetrics fm(font());
00182         const int width = fm.width(text()) + 32;
00183         if (width > size.width()) {
00184             size.setWidth(width);
00185         }
00186     }
00187 
00188     return size;
00189 }
00190 
00191 void HostLineEdit::mousePressEvent(QMouseEvent* event)
00192 {
00193     KLineEdit::mousePressEvent(event);
00194 
00195     if (event->button() == Qt::LeftButton) {
00196         // behave like a button when a mouse click has been done
00197         // inside the host editor and go to the host URL
00198         const KUrl currentUrl = m_urlNavigator->url();
00199         const KUrl newUrl(currentUrl.protocol() + "://" + text());
00200         if (currentUrl != newUrl) {
00201             m_urlNavigator->setUrl(newUrl);
00202         }
00203     }
00204 }
00205 
00207 
00208 class KUrlNavigator::Private
00209 {
00210 public:
00211     Private(KUrlNavigator* q, KFilePlacesModel* placesModel);
00212 
00213     void slotReturnPressed(const QString&);
00214     void slotReturnPressed();
00215     void slotRemoteHostActivated();
00216     void slotProtocolChanged(const QString&);
00217     void openPathSelectorMenu();
00218 
00224     void appendWidget(QWidget* widget, int stretch = 0);
00225 
00231     void switchView();
00232 
00234     void dropUrls(const KUrl::List& urls, const KUrl& destination);
00235 
00236     void updateContent();
00237 
00246     void updateButtons(const QString& path, int startIndex);
00247 
00253     void updateButtonVisibility();
00254 
00255     void switchToBreadcrumbMode();
00256 
00261     void deleteButtons();
00262 
00270     QString retrievePlacePath(const QString& path) const;
00271 
00276     bool isCompressedPath(const KUrl& path) const;
00277 
00278     bool m_editable;
00279     bool m_active;
00280     bool m_showPlacesSelector;
00281     int m_historyIndex;
00282 
00283     QHBoxLayout* m_layout;
00284 
00285     QList<HistoryElem> m_history;
00286     KFilePlacesSelector* m_placesSelector;
00287     KUrlComboBox* m_pathBox;
00288     KProtocolCombo* m_protocols;
00289     HostLineEdit* m_host;
00290     KUrlDropDownButton* m_dropDownButton;
00291     QLinkedList<KUrlNavigatorButton*> m_navButtons;
00292     KUrlButton* m_toggleEditableMode;
00293     QString m_homeUrl;
00294     QStringList m_customProtocols;
00295     KUrlNavigator* q;
00296 
00297 private:
00302     void createHostLineEdit(const QString& text);
00303 };
00304 
00305 
00306 KUrlNavigator::Private::Private(KUrlNavigator* q, KFilePlacesModel* placesModel) :
00307     m_editable(false),
00308     m_active(true),
00309     m_showPlacesSelector(placesModel != 0),
00310     m_historyIndex(0),
00311     m_layout(new QHBoxLayout),
00312     m_placesSelector(0),
00313     m_pathBox(0),
00314     m_protocols(0),
00315     m_host(0),
00316     m_dropDownButton(0),
00317     m_toggleEditableMode(0),
00318     m_customProtocols(QStringList()),
00319     q(q)
00320 {
00321     m_layout->setSpacing(0);
00322     m_layout->setMargin(0);
00323 
00324     // initialize the places selector
00325     q->setAutoFillBackground(false);
00326 
00327     if (placesModel != 0) {
00328         m_placesSelector = new KFilePlacesSelector(q, placesModel);
00329         connect(m_placesSelector, SIGNAL(placeActivated(const KUrl&)),
00330                 q, SLOT(setUrl(const KUrl&)));
00331 
00332         connect(placesModel, SIGNAL(rowsInserted(QModelIndex, int, int)),
00333                 q, SLOT(updateContent()));
00334         connect(placesModel, SIGNAL(rowsRemoved(QModelIndex, int, int)),
00335                 q, SLOT(updateContent()));
00336         connect(placesModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
00337                 q, SLOT(updateContent()));
00338     }
00339 
00340     m_dropDownButton = new KUrlDropDownButton(q);
00341     connect(m_dropDownButton, SIGNAL(clicked()),
00342             q, SLOT(openPathSelectorMenu()));
00343 
00344     // initialize the path box of the traditional view
00345     m_pathBox = new KUrlComboBox(KUrlComboBox::Both, true, q);
00346     m_pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00347     m_pathBox->installEventFilter(q);
00348 
00349     KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
00350     m_pathBox->setCompletionObject(kurlCompletion);
00351     m_pathBox->setAutoDeleteCompletionObject(true);
00352 
00353     connect(m_pathBox, SIGNAL(returnPressed(QString)),
00354             q, SLOT(slotReturnPressed(QString)));
00355     connect(m_pathBox, SIGNAL(returnPressed()),
00356             q, SLOT(slotReturnPressed()));
00357     connect(m_pathBox, SIGNAL(urlActivated(KUrl)),
00358             q, SLOT(setUrl(KUrl)));
00359 
00360     m_toggleEditableMode = new KUrlToggleButton(q);
00361     m_toggleEditableMode->setMinimumWidth(20);
00362     connect(m_toggleEditableMode, SIGNAL(clicked()),
00363             q, SLOT(switchView()));
00364 
00365     if (m_placesSelector != 0) {
00366         m_layout->addWidget(m_placesSelector);
00367     }
00368     m_layout->addWidget(m_dropDownButton);
00369     m_layout->addWidget(m_pathBox, 1);
00370     m_layout->addWidget(m_toggleEditableMode);
00371 }
00372 
00373 void KUrlNavigator::Private::appendWidget(QWidget* widget, int stretch)
00374 {
00375     m_layout->insertWidget(m_layout->count() - 1, widget, stretch);
00376 }
00377 
00378 void KUrlNavigator::Private::slotReturnPressed(const QString& text)
00379 {
00380     // Parts of the following code have been taken
00381     // from the class KateFileSelector located in
00382     // kate/app/katefileselector.hpp of Kate.
00383     // Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00384     // Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00385     // Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
00386 
00387     KUrl typedUrl(text);
00388     if (typedUrl.hasPass()) {
00389         typedUrl.setPass(QString());
00390     }
00391 
00392     QStringList urls = m_pathBox->urls();
00393     urls.removeAll(typedUrl.url());
00394     urls.prepend(typedUrl.url());
00395     m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
00396 
00397     q->setUrl(typedUrl);
00398     // The URL might have been adjusted by KUrlNavigator::setUrl(), hence
00399     // synchronize the result in the path box.
00400     m_pathBox->setUrl(q->url());
00401 
00402     emit q->returnPressed();
00403 
00404     if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00405         // Pressing Ctrl+Return automatically switches back to the breadcrumb mode.
00406         // The switch must be done asynchronously, as we are in the context of the
00407         // editor.
00408         QMetaObject::invokeMethod(q, "switchToBreadcrumbMode", Qt::QueuedConnection);
00409     }
00410 }
00411 
00412 void KUrlNavigator::Private::slotReturnPressed()
00413 {
00414     const QString text = q->uncommittedUrl().prettyUrl();
00415     slotReturnPressed(text);
00416 }
00417 
00418 void KUrlNavigator::Private::slotRemoteHostActivated()
00419 {
00420     KUrl u = q->url();
00421 
00422     KUrl n(m_protocols->currentProtocol() + "://" + m_host->text());
00423 
00424     if (n.scheme() != u.scheme() ||
00425             n.host() != u.host() ||
00426             n.user() != u.user() ||
00427             n.port() != u.port()) {
00428         u.setScheme(n.scheme());
00429         u.setHost(n.host());
00430         u.setUser(n.user());
00431         u.setPort(n.port());
00432 
00433         //TODO: get rid of this HACK for file:///!
00434         if (u.scheme() == "file") {
00435             u.setHost("");
00436             if (u.path().isEmpty()) {
00437                 u.setPath("/");
00438             }
00439         }
00440 
00441         q->setUrl(u);
00442     }
00443 }
00444 
00445 void KUrlNavigator::Private::slotProtocolChanged(const QString& protocol)
00446 {
00447     KUrl url;
00448     url.setScheme(protocol);
00449     url.setPath("/");
00450     QLinkedList<KUrlNavigatorButton*>::const_iterator it = m_navButtons.begin();
00451     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00452     while (it != itEnd) {
00453         (*it)->hide();
00454         (*it)->deleteLater();
00455         ++it;
00456     }
00457     m_navButtons.clear();
00458 
00459     if (KProtocolInfo::protocolClass(protocol) == ":local") {
00460         q->setUrl(url);
00461     } else {
00462         if (m_host == 0) {
00463             createHostLineEdit("");
00464         } else {
00465             m_host->setText("");
00466         }
00467         m_host->show();
00468         m_host->setFocus();
00469     }
00470 }
00471 
00472 void KUrlNavigator::Private::openPathSelectorMenu()
00473 {
00474     KMenu* popup = new KMenu(q);
00475 
00476     QString spacer;
00477     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00478     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00479     while (it != itEnd) {
00480         const QString text = spacer + (*it)->text();
00481         spacer.append("  ");
00482 
00483         QAction* action = new QAction(text, popup);
00484         action->setData(QVariant((*it)->index()));
00485         popup->addAction(action);
00486 
00487         ++it;
00488     }
00489 
00490     const QAction* activatedAction = popup->exec(QCursor::pos());
00491     if (activatedAction != 0) {
00492         const int index = activatedAction->data().toInt();
00493         q->setUrl(q->url(index));
00494     }
00495 
00496     popup->deleteLater();
00497 }
00498 
00499 void KUrlNavigator::Private::switchView()
00500 {
00501     m_toggleEditableMode->setFocus();
00502     m_editable = !m_editable;
00503     m_toggleEditableMode->setChecked(m_editable);
00504     updateContent();
00505     if (q->isUrlEditable()) {
00506         m_pathBox->setFocus();
00507     }
00508 
00509     emit q->requestActivation();
00510     emit q->editableStateChanged(m_editable);
00511 }
00512 
00513 void KUrlNavigator::Private::dropUrls(const KUrl::List& urls,
00514                                       const KUrl& destination)
00515 {
00516     emit q->urlsDropped(urls, destination);
00517 }
00518 
00519 void KUrlNavigator::Private::updateContent()
00520 {
00521     if (m_placesSelector != 0) {
00522         m_placesSelector->updateSelection(q->url());
00523     }
00524 
00525     if (m_editable) {
00526         delete m_protocols;
00527         m_protocols = 0;
00528         delete m_host;
00529         m_host = 0;
00530 
00531         m_dropDownButton->hide();
00532         deleteButtons();
00533         m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
00534 
00535         q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00536         m_pathBox->show();
00537         m_pathBox->setUrl(q->url());
00538     } else {
00539         const QString path = q->url().pathOrUrl();
00540 
00541         q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00542         m_pathBox->hide();
00543         m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00544 
00545         // get the data from the currently selected place
00546         KUrl placeUrl = KUrl();
00547         if (m_placesSelector != 0) {
00548             placeUrl = m_placesSelector->selectedPlaceUrl();
00549         }
00550 
00551         const QString placePath = placeUrl.isValid() ? placeUrl.pathOrUrl() : retrievePlacePath(path);
00552         const uint len = placePath.length();
00553 
00554         // calculate the start point for the URL navigator buttons by counting
00555         // the slashs inside the place URL
00556         int slashCount = 0;
00557         for (uint i = 0; i < len; ++i) {
00558             if (placePath.at(i) == QChar('/')) {
00559                 ++slashCount;
00560             }
00561         }
00562         if ((len > 0) && placePath.at(len - 1) == QChar('/')) {
00563             Q_ASSERT(slashCount > 0);
00564             --slashCount;
00565         }
00566 
00567         const KUrl currentUrl = q->url();
00568         if (!currentUrl.isLocalFile() && !placeUrl.isValid()) {
00569             QString protocol = currentUrl.scheme();
00570             if (m_protocols == 0) {
00571                 deleteButtons();
00572 
00573                 m_protocols = new KProtocolCombo(protocol, q);
00574                 const int index = m_layout->indexOf(m_dropDownButton);
00575                 m_layout->insertWidget(index, m_protocols);
00576 
00577                 if (!m_customProtocols.isEmpty()) {
00578                     m_protocols->setCustomProtocols(m_customProtocols);
00579                 }
00580                 connect(m_protocols, SIGNAL(activated(QString)),
00581                         q, SLOT(slotProtocolChanged(QString)));
00582             } else {
00583                 m_protocols->setProtocol(protocol);
00584             }
00585             m_protocols->show();
00586 
00587             if (KProtocolInfo::protocolClass(protocol) != ":local") {
00588                 QString hostText = currentUrl.host();
00589 
00590                 if (!currentUrl.user().isEmpty()) {
00591                     hostText = currentUrl.user() + '@' + hostText;
00592                 }
00593 
00594                 if (currentUrl.port() != -1) {
00595                     hostText = hostText + ':' + QString::number(currentUrl.port());
00596                 }
00597 
00598                 if (m_host == 0) {
00599                     createHostLineEdit(hostText);
00600                 } else {
00601                     m_host->setText(hostText);
00602                 }
00603                 m_host->show();
00604             } else {
00605                 delete m_host;
00606                 m_host = 0;
00607             }
00608         } else if (m_protocols != 0) {
00609             m_protocols->hide();
00610             if (m_host != 0) {
00611                 m_host->hide();
00612             }
00613         }
00614 
00615         updateButtons(path, slashCount);
00616     }
00617 }
00618 
00619 void KUrlNavigator::Private::updateButtons(const QString& path, int startIndex)
00620 {
00621     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00622     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00623     bool createButton = false;
00624     const KUrl currentUrl = q->url();
00625 
00626     int idx = startIndex;
00627     bool hasNext = true;
00628     do {
00629         createButton = (it == itEnd);
00630 
00631         const QString dirName = path.section('/', idx, idx);
00632         const bool isFirstButton = (idx == startIndex);
00633         hasNext = isFirstButton || !dirName.isEmpty();
00634         if (hasNext) {
00635             QString text;
00636             if (isFirstButton) {
00637                 // the first URL navigator button should get the name of the
00638                 // place instead of the directory name
00639                 if (m_placesSelector != 0) {
00640                     const KUrl placeUrl = m_placesSelector->selectedPlaceUrl();
00641                     text = m_placesSelector->selectedPlaceText();
00642                 }
00643                 if (text.isEmpty()) {
00644                     if (currentUrl.isLocalFile()) {
00645                         text = i18n("Custom Path");
00646                     } else {
00647                         ++idx;
00648                         continue;
00649                     }
00650                 }
00651             }
00652 
00653             KUrlNavigatorButton* button = 0;
00654             if (createButton) {
00655                 button = new KUrlNavigatorButton(idx, q);
00656                 connect(button, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
00657                         q, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
00658                 appendWidget(button);
00659             } else {
00660                 button = *it;
00661                 button->setIndex(idx);
00662             }
00663 
00664             if (isFirstButton) {
00665                 button->setText(text);
00666                 button->updateMinimumWidth();
00667             }
00668 
00669             if (createButton) {
00670                 m_navButtons.append(button);
00671             } else {
00672                 ++it;
00673             }
00674             ++idx;
00675         }
00676     } while (hasNext);
00677 
00678     // delete buttons which are not used anymore
00679     QLinkedList<KUrlNavigatorButton*>::iterator itBegin = it;
00680     while (it != itEnd) {
00681         (*it)->hide();
00682         (*it)->deleteLater();
00683         ++it;
00684     }
00685     m_navButtons.erase(itBegin, m_navButtons.end());
00686 
00687     updateButtonVisibility();
00688 }
00689 
00690 void KUrlNavigator::Private::updateButtonVisibility()
00691 {
00692     if (m_editable) {
00693         return;
00694     }
00695 
00696     const int buttonsCount = m_navButtons.count();
00697     if (m_host != 0) {
00698         const bool optimize = (buttonsCount != 0);
00699         m_host->setOptimizeWidth(optimize);
00700         if (optimize) {
00701             m_host->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00702             m_layout->setStretchFactor(m_host, 0);
00703         } else {
00704             m_host->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00705             m_layout->setStretchFactor(m_host, 1);
00706         }
00707     }
00708 
00709     if (buttonsCount == 0) {
00710         m_dropDownButton->hide();
00711         return;
00712     }
00713 
00714     int hiddenButtonsCount = 0;
00715 
00716     // subtract all widgets from the available width, that must be shown anyway
00717     int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
00718 
00719     if ((m_placesSelector != 0) && m_placesSelector->isVisible()) {
00720         availableWidth -= m_placesSelector->width();
00721     }
00722 
00723     if ((m_protocols != 0) && m_protocols->isVisible()) {
00724         availableWidth -= m_protocols->width();
00725     }
00726 
00727     if ((m_host != 0) && m_host->isVisible()) {
00728         availableWidth -= m_host->width();
00729     }
00730 
00731     // check whether buttons must be hidden at all...
00732     int requiredButtonWidth = 0;
00733     foreach (KUrlNavigatorButton* button, m_navButtons) {
00734         requiredButtonWidth += button->minimumWidth();
00735     }
00736     if (requiredButtonWidth > availableWidth) {
00737         // At least one button must be hidden. This implies that the
00738         // drop-down button must get visible, which again decreases the
00739         // available width.
00740         availableWidth -= m_dropDownButton->width();
00741     }
00742 
00743     // hide buttons...
00744     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.end();
00745     const QLinkedList<KUrlNavigatorButton*>::const_iterator itBegin = m_navButtons.begin();
00746     while (it != itBegin) {
00747         --it;
00748         KUrlNavigatorButton* button = (*it);
00749         availableWidth -= button->minimumWidth();
00750         if (availableWidth <= 0) {
00751             button->hide();
00752             ++hiddenButtonsCount;
00753         }
00754         else {
00755             button->show();
00756         }
00757     }
00758 
00759     Q_ASSERT(hiddenButtonsCount <= buttonsCount);
00760     if (hiddenButtonsCount == buttonsCount) {
00761         // assure that at least one button is visible
00762         hiddenButtonsCount = buttonsCount - 1;
00763     }
00764 
00765     int index = 0;
00766     it = m_navButtons.begin();
00767     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00768     while (it != itEnd) {
00769         (*it)->setVisible(index >= hiddenButtonsCount);
00770         ++it;
00771         ++index;
00772     }
00773 
00774     m_dropDownButton->setVisible(hiddenButtonsCount != 0);
00775 }
00776 
00777 void KUrlNavigator::Private::switchToBreadcrumbMode()
00778 {
00779     q->setUrlEditable(false);
00780 }
00781 
00782 void KUrlNavigator::Private::deleteButtons()
00783 {
00784     foreach (KUrlNavigatorButton* button, m_navButtons) {
00785         button->hide();
00786         button->deleteLater();
00787     }
00788     m_navButtons.clear();
00789 }
00790 
00791 QString KUrlNavigator::Private::retrievePlacePath(const QString& path) const
00792 {
00793     int idx = path.indexOf(QLatin1String("///"));
00794     if (idx >= 0) {
00795         idx += 3;
00796     } else {
00797         idx = path.indexOf(QLatin1String("//"));
00798         idx = path.indexOf(QLatin1Char('/'), (idx < 0) ? 0 : idx + 2);
00799     }
00800     return (idx < 0) ? path : path.left(idx);
00801 }
00802 
00803 bool KUrlNavigator::Private::isCompressedPath(const KUrl& url) const
00804 {
00805     const KMimeType::Ptr mime = KMimeType::findByPath(url.path(KUrl::RemoveTrailingSlash));
00806     // Note: this list of MIME types depends on the protocols implemented by kio_archive
00807     return  mime->is("application/x-compressed-tar") ||
00808             mime->is("application/x-bzip-compressed-tar") ||
00809             mime->is("application/x-tar") ||
00810             mime->is("application/x-tarz") ||
00811             mime->is("application/x-tzo") || // (not sure KTar supports those?)
00812             mime->is("application/zip") ||
00813             mime->is("application/x-archive");
00814 }
00815 
00816 void KUrlNavigator::Private::createHostLineEdit(const QString& text)
00817 {
00818     Q_ASSERT(m_host == 0);
00819 
00820     m_host = new HostLineEdit(text, q);
00821     m_host->setClearButtonShown(true);
00822 
00823     const int index = m_layout->indexOf(m_dropDownButton);
00824     m_layout->insertWidget(index, m_host);
00825 
00826     connect(m_host, SIGNAL(editingFinished()),
00827             q, SLOT(slotRemoteHostActivated()));
00828     connect(m_host, SIGNAL(returnPressed()),
00829             q, SIGNAL(returnPressed()));
00830 }
00831 
00833 
00834 KUrlNavigator::KUrlNavigator(KFilePlacesModel* placesModel,
00835                              const KUrl& url,
00836                              QWidget* parent) :
00837     QWidget(parent),
00838     d(new Private(this, placesModel))
00839 {
00840     d->m_history.prepend(HistoryElem(url));
00841 
00842     const QFont font = KGlobalSettings::generalFont();
00843     setFont(font);
00844 
00845     const int minHeight = d->m_pathBox->sizeHint().height();
00846     setMinimumHeight(minHeight);
00847 
00848     setLayout(d->m_layout);
00849     setMinimumWidth(100);
00850 
00851     d->updateContent();
00852 }
00853 
00854 KUrlNavigator::~KUrlNavigator()
00855 {
00856     delete d;
00857 }
00858 
00859 const KUrl& KUrlNavigator::url() const
00860 {
00861     Q_ASSERT(!d->m_history.empty());
00862     return d->m_history[d->m_historyIndex].url();
00863 }
00864 
00865 KUrl KUrlNavigator::uncommittedUrl() const
00866 {
00867     if (isUrlEditable()) {
00868         return KUrl(d->m_pathBox->currentText());
00869     } else {
00870         return KUrl(d->m_protocols->currentProtocol() + "://" + d->m_host->text());
00871     }
00872 }
00873 
00874 KUrl KUrlNavigator::url(int index) const
00875 {
00876     if (index < 0) {
00877         index = 0;
00878     }
00879 
00880     // keep scheme, hostname etc. maybe we will need this in the future
00881     // for e.g. browsing ftp repositories.
00882     KUrl newUrl = url();
00883     newUrl.setPath(QString());
00884 
00885     QString pathOrUrl = url().pathOrUrl();
00886     if (!pathOrUrl.isEmpty()) {
00887         if (index == 0) {
00888             // prevent the last "/" from being stripped
00889             // or we end up with an empty path
00890 #ifdef Q_OS_WIN
00891             pathOrUrl = pathOrUrl.length() > 2 ? pathOrUrl.left(3) : QDir::rootPath();
00892 #else
00893             pathOrUrl = QLatin1String("/");
00894 #endif
00895         } else {
00896             pathOrUrl = pathOrUrl.section('/', 0, index);
00897         }
00898     }
00899 
00900     newUrl.setPath(KUrl(pathOrUrl).path());
00901     return newUrl;
00902 }
00903 
00904 bool KUrlNavigator::goBack()
00905 {
00906     const int count = d->m_history.count();
00907     if (d->m_historyIndex < count - 1) {
00908         ++d->m_historyIndex;
00909         d->updateContent();
00910         emit historyChanged();
00911         emit urlChanged(url());
00912         return true;
00913     }
00914 
00915     return false;
00916 }
00917 
00918 bool KUrlNavigator::goForward()
00919 {
00920     if (d->m_historyIndex > 0) {
00921         --d->m_historyIndex;
00922         d->updateContent();
00923         emit historyChanged();
00924         emit urlChanged(url());
00925         return true;
00926     }
00927 
00928     return false;
00929 }
00930 
00931 bool KUrlNavigator::goUp()
00932 {
00933     const KUrl& currentUrl = url();
00934     const KUrl upUrl = currentUrl.upUrl();
00935     if (upUrl != currentUrl) {
00936         setUrl(upUrl);
00937         return true;
00938     }
00939 
00940     return false;
00941 }
00942 
00943 void KUrlNavigator::goHome()
00944 {
00945     if (d->m_homeUrl.isEmpty()) {
00946         setUrl(QDir::homePath());
00947     } else {
00948         setUrl(d->m_homeUrl);
00949     }
00950 }
00951 
00952 void KUrlNavigator::setHomeUrl(const QString& homeUrl)
00953 {
00954     d->m_homeUrl = homeUrl;
00955 }
00956 
00957 void KUrlNavigator::setUrlEditable(bool editable)
00958 {
00959     if (d->m_editable != editable) {
00960         d->switchView();
00961     }
00962 }
00963 
00964 bool KUrlNavigator::isUrlEditable() const
00965 {
00966     return d->m_editable;
00967 }
00968 
00969 void KUrlNavigator::setActive(bool active)
00970 {
00971     if (active != d->m_active) {
00972         d->m_active = active;
00973         update();
00974         if (active) {
00975             emit activated();
00976         }
00977     }
00978 }
00979 
00980 bool KUrlNavigator::isActive() const
00981 {
00982     return d->m_active;
00983 }
00984 
00985 void KUrlNavigator::setPlacesSelectorVisible(bool visible)
00986 {
00987     if (visible == d->m_showPlacesSelector) {
00988         return;
00989     }
00990 
00991     if (visible  && (d->m_placesSelector == 0)) {
00992         // the places selector cannot get visible as no
00993         // places model is available
00994         return;
00995     }
00996 
00997     d->m_showPlacesSelector = visible;
00998     d->m_placesSelector->setVisible(visible);
00999 }
01000 
01001 bool KUrlNavigator::isPlacesSelectorVisible() const
01002 {
01003     return d->m_showPlacesSelector;
01004 }
01005 
01006 void KUrlNavigator::setUrl(const KUrl& url)
01007 {
01008     QString urlStr(KUrlCompletion::replacedPath(url.pathOrUrl(), true, true));
01009 
01010     if (urlStr.length() > 0 && urlStr.at(0) == '~') {
01011         // replace '~' by the home directory
01012         urlStr.remove(0, 1);
01013         urlStr.insert(0, QDir::homePath());
01014     }
01015 
01016     if ((url.protocol() == "tar") || (url.protocol() == "zip")) {
01017         // The URL represents a tar- or zip-file. Check whether
01018         // the URL is really part of the tar- or zip-file, otherwise
01019         // replace it by the local path again.
01020         bool insideCompressedPath = d->isCompressedPath(url);
01021         if (!insideCompressedPath) {
01022             KUrl prevUrl = url;
01023             KUrl parentUrl = url.upUrl();
01024             while (parentUrl != prevUrl) {
01025                 if (d->isCompressedPath(parentUrl)) {
01026                     insideCompressedPath = true;
01027                     break;
01028                 }
01029                 prevUrl = parentUrl;
01030                 parentUrl = parentUrl.upUrl();
01031             }
01032         }
01033         if (!insideCompressedPath) {
01034             // drop the tar: or zip: protocol since we are not
01035             // inside the compressed path anymore
01036             urlStr = url.path();
01037         }
01038     }
01039 
01040     const KUrl transformedUrl(urlStr);
01041 
01042     // Check whether current history element has the same URL.
01043     // If this is the case, just ignore setting the URL.
01044     const HistoryElem& historyElem = d->m_history[d->m_historyIndex];
01045     const bool isUrlEqual = transformedUrl.equals(historyElem.url(), KUrl::CompareWithoutTrailingSlash) ||
01046                             !transformedUrl.isValid() && (urlStr == historyElem.url().url());
01047     if (isUrlEqual) {
01048         return;
01049     }
01050 
01051     if (d->m_historyIndex > 0) {
01052         // If an URL is set when the history index is not at the end (= 0),
01053         // then clear all previous history elements so that a new history
01054         // tree is started from the current position.
01055         QList<HistoryElem>::iterator begin = d->m_history.begin();
01056         QList<HistoryElem>::iterator end = begin + d->m_historyIndex;
01057         d->m_history.erase(begin, end);
01058         d->m_historyIndex = 0;
01059     }
01060 
01061     Q_ASSERT(d->m_historyIndex == 0);
01062     d->m_history.insert(0, HistoryElem(transformedUrl));
01063 
01064     // Prevent an endless growing of the history: remembering
01065     // the last 100 Urls should be enough...
01066     const int historyMax = 100;
01067     if (d->m_history.size() > historyMax) {
01068         QList<HistoryElem>::iterator begin = d->m_history.begin() + historyMax;
01069         QList<HistoryElem>::iterator end = d->m_history.end();
01070         d->m_history.erase(begin, end);
01071     }
01072 
01073     emit historyChanged();
01074     emit urlChanged(transformedUrl);
01075 
01076     d->updateContent();
01077 
01078     requestActivation();
01079 }
01080 
01081 void KUrlNavigator::requestActivation()
01082 {
01083     setActive(true);
01084 }
01085 
01086 void KUrlNavigator::saveRootUrl(const KUrl& url)
01087 {
01088     HistoryElem& hist = d->m_history[d->m_historyIndex];
01089     hist.setRootUrl(url);
01090 }
01091 
01092 void KUrlNavigator::savePosition(int x, int y)
01093 {
01094     HistoryElem& hist = d->m_history[d->m_historyIndex];
01095     hist.setContentsX(x);
01096     hist.setContentsY(y);
01097 }
01098 
01099 void KUrlNavigator::keyReleaseEvent(QKeyEvent* event)
01100 {
01101     QWidget::keyReleaseEvent(event);
01102     if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
01103         setUrlEditable(false);
01104     }
01105 }
01106 
01107 void KUrlNavigator::mouseReleaseEvent(QMouseEvent* event)
01108 {
01109     if (event->button() == Qt::MidButton) {
01110         QClipboard* clipboard = QApplication::clipboard();
01111         const QMimeData* mimeData = clipboard->mimeData();
01112         if (mimeData->hasText()) {
01113             const QString text = mimeData->text();
01114             setUrl(KUrl(text));
01115         }
01116     }
01117     QWidget::mouseReleaseEvent(event);
01118 }
01119 
01120 void KUrlNavigator::resizeEvent(QResizeEvent* event)
01121 {
01122     QTimer::singleShot(0, this, SLOT(updateButtonVisibility()));
01123     QWidget::resizeEvent(event);
01124 }
01125 
01126 bool KUrlNavigator::eventFilter(QObject* watched, QEvent* event)
01127 {
01128     if ((watched == d->m_pathBox) && (event->type() == QEvent::FocusIn)) {
01129         requestActivation();
01130         setFocus();
01131     }
01132 
01133     return QWidget::eventFilter(watched, event);
01134 }
01135 
01136 int KUrlNavigator::historySize() const
01137 {
01138     return d->m_history.count();
01139 }
01140 
01141 int KUrlNavigator::historyIndex() const
01142 {
01143     return d->m_historyIndex;
01144 }
01145 
01146 const KUrl& KUrlNavigator::savedRootUrl() const
01147 {
01148     const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01149     return histElem.rootUrl();
01150 }
01151 
01152 QPoint KUrlNavigator::savedPosition() const
01153 {
01154     const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01155     return QPoint(histElem.contentsX(), histElem.contentsY());
01156 }
01157 
01158 KUrlComboBox* KUrlNavigator::editor() const
01159 {
01160     return d->m_pathBox;
01161 }
01162 
01163 void KUrlNavigator::setCustomProtocols(const QStringList &protocols)
01164 {
01165     d->m_customProtocols = protocols;
01166 
01167     d->m_protocols->setCustomProtocols(d->m_customProtocols);
01168 }
01169 
01170 QStringList KUrlNavigator::customProtocols() const
01171 {
01172     return d->m_customProtocols;
01173 }
01174 
01175 void KUrlNavigator::setFocus()
01176 {
01177     if (isUrlEditable()) {
01178         d->m_pathBox->setFocus();
01179     } else if (d->m_host) {
01180         d->m_host->setFocus();
01181     } else {
01182         QWidget::setFocus();
01183     }
01184 }
01185 
01186 #include "kurlnavigator.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.6
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