• 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 
00348     KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
00349     m_pathBox->setCompletionObject(kurlCompletion);
00350     m_pathBox->setAutoDeleteCompletionObject(true);
00351 
00352     connect(m_pathBox, SIGNAL(returnPressed(QString)),
00353             q, SLOT(slotReturnPressed(QString)));
00354     connect(m_pathBox, SIGNAL(returnPressed()),
00355             q, SLOT(slotReturnPressed()));
00356     connect(m_pathBox, SIGNAL(urlActivated(KUrl)),
00357             q, SLOT(setUrl(KUrl)));
00358 
00359     m_toggleEditableMode = new KUrlToggleButton(q);
00360     m_toggleEditableMode->setMinimumWidth(20);
00361     connect(m_toggleEditableMode, SIGNAL(clicked()),
00362             q, SLOT(switchView()));
00363 
00364     if (m_placesSelector != 0) {
00365         m_layout->addWidget(m_placesSelector);
00366     }
00367     m_layout->addWidget(m_dropDownButton);
00368     m_layout->addWidget(m_pathBox, 1);
00369     m_layout->addWidget(m_toggleEditableMode);
00370 }
00371 
00372 void KUrlNavigator::Private::appendWidget(QWidget* widget, int stretch)
00373 {
00374     m_layout->insertWidget(m_layout->count() - 1, widget, stretch);
00375 }
00376 
00377 void KUrlNavigator::Private::slotReturnPressed(const QString& text)
00378 {
00379     // Parts of the following code have been taken
00380     // from the class KateFileSelector located in
00381     // kate/app/katefileselector.hpp of Kate.
00382     // Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00383     // Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00384     // Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
00385 
00386     KUrl typedUrl(text);
00387     if (typedUrl.hasPass()) {
00388         typedUrl.setPass(QString());
00389     }
00390 
00391     QStringList urls = m_pathBox->urls();
00392     urls.removeAll(typedUrl.url());
00393     urls.prepend(typedUrl.url());
00394     m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
00395 
00396     q->setUrl(typedUrl);
00397     // The URL might have been adjusted by KUrlNavigator::setUrl(), hence
00398     // synchronize the result in the path box.
00399     m_pathBox->setUrl(q->url());
00400 
00401     emit q->returnPressed();
00402 
00403     if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00404         // Pressing Ctrl+Return automatically switches back to the breadcrumb mode.
00405         // The switch must be done asynchronously, as we are in the context of the
00406         // editor.
00407         QMetaObject::invokeMethod(q, "switchToBreadcrumbMode", Qt::QueuedConnection);
00408     }
00409 }
00410 
00411 void KUrlNavigator::Private::slotReturnPressed()
00412 {
00413     const QString text = q->uncommittedUrl().prettyUrl();
00414     slotReturnPressed(text);
00415 }
00416 
00417 void KUrlNavigator::Private::slotRemoteHostActivated()
00418 {
00419     KUrl u = q->url();
00420 
00421     KUrl n(m_protocols->currentProtocol() + "://" + m_host->text());
00422 
00423     if (n.scheme() != u.scheme() ||
00424             n.host() != u.host() ||
00425             n.user() != u.user() ||
00426             n.port() != u.port()) {
00427         u.setScheme(n.scheme());
00428         u.setHost(n.host());
00429         u.setUser(n.user());
00430         u.setPort(n.port());
00431 
00432         //TODO: get rid of this HACK for file:///!
00433         if (u.scheme() == "file") {
00434             u.setHost("");
00435             if (u.path().isEmpty()) {
00436                 u.setPath("/");
00437             }
00438         }
00439 
00440         q->setUrl(u);
00441     }
00442 }
00443 
00444 void KUrlNavigator::Private::slotProtocolChanged(const QString& protocol)
00445 {
00446     KUrl url;
00447     url.setScheme(protocol);
00448     url.setPath("/");
00449     QLinkedList<KUrlNavigatorButton*>::const_iterator it = m_navButtons.begin();
00450     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00451     while (it != itEnd) {
00452         (*it)->hide();
00453         (*it)->deleteLater();
00454         ++it;
00455     }
00456     m_navButtons.clear();
00457 
00458     if (KProtocolInfo::protocolClass(protocol) == ":local") {
00459         q->setUrl(url);
00460     } else {
00461         if (m_host == 0) {
00462             createHostLineEdit("");
00463         } else {
00464             m_host->setText("");
00465         }
00466         m_host->show();
00467         m_host->setFocus();
00468     }
00469 }
00470 
00471 void KUrlNavigator::Private::openPathSelectorMenu()
00472 {
00473     KMenu* popup = new KMenu(q);
00474 
00475     QString spacer;
00476     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00477     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00478     while (it != itEnd) {
00479         const QString text = spacer + (*it)->text();
00480         spacer.append("  ");
00481 
00482         QAction* action = new QAction(text, popup);
00483         action->setData(QVariant((*it)->index()));
00484         popup->addAction(action);
00485 
00486         ++it;
00487     }
00488 
00489     const QAction* activatedAction = popup->exec(QCursor::pos());
00490     if (activatedAction != 0) {
00491         const int index = activatedAction->data().toInt();
00492         q->setUrl(q->url(index));
00493     }
00494 
00495     popup->deleteLater();
00496 }
00497 
00498 void KUrlNavigator::Private::switchView()
00499 {
00500     m_toggleEditableMode->setFocus();
00501     m_editable = !m_editable;
00502     m_toggleEditableMode->setChecked(m_editable);
00503     updateContent();
00504     if (q->isUrlEditable()) {
00505         m_pathBox->setFocus();
00506     }
00507 
00508     emit q->requestActivation();
00509     emit q->editableStateChanged(m_editable);
00510 }
00511 
00512 void KUrlNavigator::Private::dropUrls(const KUrl::List& urls,
00513                                       const KUrl& destination)
00514 {
00515     emit q->urlsDropped(urls, destination);
00516 }
00517 
00518 void KUrlNavigator::Private::updateContent()
00519 {
00520     if (m_placesSelector != 0) {
00521         m_placesSelector->updateSelection(q->url());
00522     }
00523 
00524     if (m_editable) {
00525         delete m_protocols;
00526         m_protocols = 0;
00527         delete m_host;
00528         m_host = 0;
00529 
00530         m_dropDownButton->hide();
00531         deleteButtons();
00532         m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
00533 
00534         q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00535         m_pathBox->show();
00536         m_pathBox->setUrl(q->url());
00537     } else {
00538         const QString path = q->url().pathOrUrl();
00539 
00540         q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00541         m_pathBox->hide();
00542         m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00543 
00544         // get the data from the currently selected place
00545         KUrl placeUrl = KUrl();
00546         if (m_placesSelector != 0) {
00547             placeUrl = m_placesSelector->selectedPlaceUrl();
00548         }
00549 
00550         const QString placePath = placeUrl.isValid() ? placeUrl.pathOrUrl() : retrievePlacePath(path);
00551         const uint len = placePath.length();
00552 
00553         // calculate the start point for the URL navigator buttons by counting
00554         // the slashs inside the place URL
00555         int slashCount = 0;
00556         for (uint i = 0; i < len; ++i) {
00557             if (placePath.at(i) == QChar('/')) {
00558                 ++slashCount;
00559             }
00560         }
00561         if ((len > 0) && placePath.at(len - 1) == QChar('/')) {
00562             Q_ASSERT(slashCount > 0);
00563             --slashCount;
00564         }
00565 
00566         const KUrl currentUrl = q->url();
00567         if (!currentUrl.isLocalFile() && !placeUrl.isValid()) {
00568             QString protocol = currentUrl.scheme();
00569             if (m_protocols == 0) {
00570                 deleteButtons();
00571 
00572                 m_protocols = new KProtocolCombo(protocol, q);
00573                 const int index = m_layout->indexOf(m_dropDownButton);
00574                 m_layout->insertWidget(index, m_protocols);
00575 
00576                 if (!m_customProtocols.isEmpty()) {
00577                     m_protocols->setCustomProtocols(m_customProtocols);
00578                 }
00579                 connect(m_protocols, SIGNAL(activated(QString)),
00580                         q, SLOT(slotProtocolChanged(QString)));
00581             } else {
00582                 m_protocols->setProtocol(protocol);
00583             }
00584             m_protocols->show();
00585 
00586             if (KProtocolInfo::protocolClass(protocol) != ":local") {
00587                 QString hostText = currentUrl.host();
00588 
00589                 if (!currentUrl.user().isEmpty()) {
00590                     hostText = currentUrl.user() + '@' + hostText;
00591                 }
00592 
00593                 if (currentUrl.port() != -1) {
00594                     hostText = hostText + ':' + QString::number(currentUrl.port());
00595                 }
00596 
00597                 if (m_host == 0) {
00598                     createHostLineEdit(hostText);
00599                 } else {
00600                     m_host->setText(hostText);
00601                 }
00602                 m_host->show();
00603             } else {
00604                 delete m_host;
00605                 m_host = 0;
00606             }
00607         } else if (m_protocols != 0) {
00608             m_protocols->hide();
00609             if (m_host != 0) {
00610                 m_host->hide();
00611             }
00612         }
00613 
00614         updateButtons(path, slashCount);
00615     }
00616 }
00617 
00618 void KUrlNavigator::Private::updateButtons(const QString& path, int startIndex)
00619 {
00620     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.begin();
00621     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00622     bool createButton = false;
00623     const KUrl currentUrl = q->url();
00624 
00625     int idx = startIndex;
00626     bool hasNext = true;
00627     do {
00628         createButton = (it == itEnd);
00629 
00630         const QString dirName = path.section('/', idx, idx);
00631         const bool isFirstButton = (idx == startIndex);
00632         hasNext = isFirstButton || !dirName.isEmpty();
00633         if (hasNext) {
00634             QString text;
00635             if (isFirstButton) {
00636                 // the first URL navigator button should get the name of the
00637                 // place instead of the directory name
00638                 if (m_placesSelector != 0) {
00639                     const KUrl placeUrl = m_placesSelector->selectedPlaceUrl();
00640                     text = m_placesSelector->selectedPlaceText();
00641                 }
00642                 if (text.isEmpty()) {
00643                     if (currentUrl.isLocalFile()) {
00644                         text = i18n("Custom Path");
00645                     } else {
00646                         ++idx;
00647                         continue;
00648                     }
00649                 }
00650             }
00651 
00652             KUrlNavigatorButton* button = 0;
00653             if (createButton) {
00654                 button = new KUrlNavigatorButton(idx, q);
00655                 connect(button, SIGNAL(urlsDropped(const KUrl::List&, const KUrl&)),
00656                         q, SLOT(dropUrls(const KUrl::List&, const KUrl&)));
00657                 appendWidget(button);
00658             } else {
00659                 button = *it;
00660                 button->setIndex(idx);
00661             }
00662 
00663             if (isFirstButton) {
00664                 button->setText(text);
00665                 button->updateMinimumWidth();
00666             }
00667 
00668             if (createButton) {
00669                 m_navButtons.append(button);
00670             } else {
00671                 ++it;
00672             }
00673             ++idx;
00674         }
00675     } while (hasNext);
00676 
00677     // delete buttons which are not used anymore
00678     QLinkedList<KUrlNavigatorButton*>::iterator itBegin = it;
00679     while (it != itEnd) {
00680         (*it)->hide();
00681         (*it)->deleteLater();
00682         ++it;
00683     }
00684     m_navButtons.erase(itBegin, m_navButtons.end());
00685 
00686     updateButtonVisibility();
00687 }
00688 
00689 void KUrlNavigator::Private::updateButtonVisibility()
00690 {
00691     if (m_editable) {
00692         return;
00693     }
00694 
00695     const int buttonsCount = m_navButtons.count();
00696     if (m_host != 0) {
00697         const bool optimize = (buttonsCount != 0);
00698         m_host->setOptimizeWidth(optimize);
00699         if (optimize) {
00700             m_host->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
00701             m_layout->setStretchFactor(m_host, 0);
00702         } else {
00703             m_host->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
00704             m_layout->setStretchFactor(m_host, 1);
00705         }
00706     }
00707 
00708     if (buttonsCount == 0) {
00709         m_dropDownButton->hide();
00710         return;
00711     }
00712 
00713     int hiddenButtonsCount = 0;
00714 
00715     // subtract all widgets from the available width, that must be shown anyway
00716     int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
00717 
00718     if ((m_placesSelector != 0) && m_placesSelector->isVisible()) {
00719         availableWidth -= m_placesSelector->width();
00720     }
00721 
00722     if ((m_protocols != 0) && m_protocols->isVisible()) {
00723         availableWidth -= m_protocols->width();
00724     }
00725 
00726     if ((m_host != 0) && m_host->isVisible()) {
00727         availableWidth -= m_host->width();
00728     }
00729 
00730     // check whether buttons must be hidden at all...
00731     int requiredButtonWidth = 0;
00732     foreach (KUrlNavigatorButton* button, m_navButtons) {
00733         requiredButtonWidth += button->minimumWidth();
00734     }
00735     if (requiredButtonWidth > availableWidth) {
00736         // At least one button must be hidden. This implies that the
00737         // drop-down button must get visible, which again decreases the
00738         // available width.
00739         availableWidth -= m_dropDownButton->width();
00740     }
00741 
00742     // hide buttons...
00743     QLinkedList<KUrlNavigatorButton*>::iterator it = m_navButtons.end();
00744     const QLinkedList<KUrlNavigatorButton*>::const_iterator itBegin = m_navButtons.begin();
00745     while (it != itBegin) {
00746         --it;
00747         KUrlNavigatorButton* button = (*it);
00748         availableWidth -= button->minimumWidth();
00749         if (availableWidth <= 0) {
00750             button->hide();
00751             ++hiddenButtonsCount;
00752         }
00753         else {
00754             button->show();
00755         }
00756     }
00757 
00758     Q_ASSERT(hiddenButtonsCount <= buttonsCount);
00759     if (hiddenButtonsCount == buttonsCount) {
00760         // assure that at least one button is visible
00761         hiddenButtonsCount = buttonsCount - 1;
00762     }
00763 
00764     int index = 0;
00765     it = m_navButtons.begin();
00766     const QLinkedList<KUrlNavigatorButton*>::const_iterator itEnd = m_navButtons.end();
00767     while (it != itEnd) {
00768         (*it)->setVisible(index >= hiddenButtonsCount);
00769         ++it;
00770         ++index;
00771     }
00772 
00773     m_dropDownButton->setVisible(hiddenButtonsCount != 0);
00774 }
00775 
00776 void KUrlNavigator::Private::switchToBreadcrumbMode()
00777 {
00778     q->setUrlEditable(false);
00779 }
00780 
00781 void KUrlNavigator::Private::deleteButtons()
00782 {
00783     foreach (KUrlNavigatorButton* button, m_navButtons) {
00784         button->hide();
00785         button->deleteLater();
00786     }
00787     m_navButtons.clear();
00788 }
00789 
00790 QString KUrlNavigator::Private::retrievePlacePath(const QString& path) const
00791 {
00792     int idx = path.indexOf(QLatin1String("///"));
00793     if (idx >= 0) {
00794         idx += 3;
00795     } else {
00796         idx = path.indexOf(QLatin1String("//"));
00797         idx = path.indexOf(QLatin1Char('/'), (idx < 0) ? 0 : idx + 2);
00798     }
00799     return (idx < 0) ? path : path.left(idx);
00800 }
00801 
00802 bool KUrlNavigator::Private::isCompressedPath(const KUrl& url) const
00803 {
00804     const KMimeType::Ptr mime = KMimeType::findByPath(url.path(KUrl::RemoveTrailingSlash));
00805     // Note: this list of MIME types depends on the protocols implemented by kio_archive
00806     return  mime->is("application/x-compressed-tar") ||
00807             mime->is("application/x-bzip-compressed-tar") ||
00808             mime->is("application/x-tar") ||
00809             mime->is("application/x-tarz") ||
00810             mime->is("application/x-tzo") || // (not sure KTar supports those?)
00811             mime->is("application/zip") ||
00812             mime->is("application/x-archive");
00813 }
00814 
00815 void KUrlNavigator::Private::createHostLineEdit(const QString& text)
00816 {
00817     Q_ASSERT(m_host == 0);
00818 
00819     m_host = new HostLineEdit(text, q);
00820     m_host->setClearButtonShown(true);
00821 
00822     const int index = m_layout->indexOf(m_dropDownButton);
00823     m_layout->insertWidget(index, m_host);
00824 
00825     connect(m_host, SIGNAL(editingFinished()),
00826             q, SLOT(slotRemoteHostActivated()));
00827     connect(m_host, SIGNAL(returnPressed()),
00828             q, SIGNAL(returnPressed()));
00829 }
00830 
00832 
00833 KUrlNavigator::KUrlNavigator(KFilePlacesModel* placesModel,
00834                              const KUrl& url,
00835                              QWidget* parent) :
00836     QWidget(parent),
00837     d(new Private(this, placesModel))
00838 {
00839     d->m_history.prepend(HistoryElem(url));
00840 
00841     const QFont font = KGlobalSettings::generalFont();
00842     setFont(font);
00843 
00844     const int minHeight = d->m_pathBox->sizeHint().height();
00845     setMinimumHeight(minHeight);
00846 
00847     setLayout(d->m_layout);
00848     setMinimumWidth(100);
00849 
00850     d->updateContent();
00851 }
00852 
00853 KUrlNavigator::~KUrlNavigator()
00854 {
00855     delete d;
00856 }
00857 
00858 const KUrl& KUrlNavigator::url() const
00859 {
00860     Q_ASSERT(!d->m_history.empty());
00861     return d->m_history[d->m_historyIndex].url();
00862 }
00863 
00864 KUrl KUrlNavigator::uncommittedUrl() const
00865 {
00866     if (isUrlEditable()) {
00867         return KUrl(d->m_pathBox->currentText());
00868     } else {
00869         return KUrl(d->m_protocols->currentProtocol() + "://" + d->m_host->text());
00870     }
00871 }
00872 
00873 KUrl KUrlNavigator::url(int index) const
00874 {
00875     if (index < 0) {
00876         index = 0;
00877     }
00878 
00879     // keep scheme, hostname etc. maybe we will need this in the future
00880     // for e.g. browsing ftp repositories.
00881     KUrl newUrl = url();
00882     newUrl.setPath(QString());
00883 
00884     QString pathOrUrl = url().pathOrUrl();
00885     if (!pathOrUrl.isEmpty()) {
00886         if (index == 0) {
00887             // prevent the last "/" from being stripped
00888             // or we end up with an empty path
00889 #ifdef Q_OS_WIN
00890             pathOrUrl = pathOrUrl.length() > 2 ? pathOrUrl.left(3) : QDir::rootPath();
00891 #else
00892             pathOrUrl = QLatin1String("/");
00893 #endif
00894         } else {
00895             pathOrUrl = pathOrUrl.section('/', 0, index);
00896         }
00897     }
00898 
00899     newUrl.setPath(KUrl(pathOrUrl).path());
00900     return newUrl;
00901 }
00902 
00903 bool KUrlNavigator::goBack()
00904 {
00905     const int count = d->m_history.count();
00906     if (d->m_historyIndex < count - 1) {
00907         ++d->m_historyIndex;
00908         d->updateContent();
00909         emit historyChanged();
00910         emit urlChanged(url());
00911         return true;
00912     }
00913 
00914     return false;
00915 }
00916 
00917 bool KUrlNavigator::goForward()
00918 {
00919     if (d->m_historyIndex > 0) {
00920         --d->m_historyIndex;
00921         d->updateContent();
00922         emit historyChanged();
00923         emit urlChanged(url());
00924         return true;
00925     }
00926 
00927     return false;
00928 }
00929 
00930 bool KUrlNavigator::goUp()
00931 {
00932     const KUrl& currentUrl = url();
00933     const KUrl upUrl = currentUrl.upUrl();
00934     if (upUrl != currentUrl) {
00935         setUrl(upUrl);
00936         return true;
00937     }
00938 
00939     return false;
00940 }
00941 
00942 void KUrlNavigator::goHome()
00943 {
00944     if (d->m_homeUrl.isEmpty()) {
00945         setUrl(QDir::homePath());
00946     } else {
00947         setUrl(d->m_homeUrl);
00948     }
00949 }
00950 
00951 void KUrlNavigator::setHomeUrl(const QString& homeUrl)
00952 {
00953     d->m_homeUrl = homeUrl;
00954 }
00955 
00956 void KUrlNavigator::setUrlEditable(bool editable)
00957 {
00958     if (d->m_editable != editable) {
00959         d->switchView();
00960     }
00961 }
00962 
00963 bool KUrlNavigator::isUrlEditable() const
00964 {
00965     return d->m_editable;
00966 }
00967 
00968 void KUrlNavigator::setActive(bool active)
00969 {
00970     if (active != d->m_active) {
00971         d->m_active = active;
00972         update();
00973         if (active) {
00974             emit activated();
00975         }
00976     }
00977 }
00978 
00979 bool KUrlNavigator::isActive() const
00980 {
00981     return d->m_active;
00982 }
00983 
00984 void KUrlNavigator::setPlacesSelectorVisible(bool visible)
00985 {
00986     if (visible == d->m_showPlacesSelector) {
00987         return;
00988     }
00989 
00990     if (visible  && (d->m_placesSelector == 0)) {
00991         // the places selector cannot get visible as no
00992         // places model is available
00993         return;
00994     }
00995 
00996     d->m_showPlacesSelector = visible;
00997     d->m_placesSelector->setVisible(visible);
00998 }
00999 
01000 bool KUrlNavigator::isPlacesSelectorVisible() const
01001 {
01002     return d->m_showPlacesSelector;
01003 }
01004 
01005 void KUrlNavigator::setUrl(const KUrl& url)
01006 {
01007     QString urlStr(KUrlCompletion::replacedPath(url.pathOrUrl(), true, true));
01008 
01009     if (urlStr.length() > 0 && urlStr.at(0) == '~') {
01010         // replace '~' by the home directory
01011         urlStr.remove(0, 1);
01012         urlStr.insert(0, QDir::homePath());
01013     }
01014 
01015     if ((url.protocol() == "tar") || (url.protocol() == "zip")) {
01016         // The URL represents a tar- or zip-file. Check whether
01017         // the URL is really part of the tar- or zip-file, otherwise
01018         // replace it by the local path again.
01019         bool insideCompressedPath = d->isCompressedPath(url);
01020         if (!insideCompressedPath) {
01021             KUrl prevUrl = url;
01022             KUrl parentUrl = url.upUrl();
01023             while (parentUrl != prevUrl) {
01024                 if (d->isCompressedPath(parentUrl)) {
01025                     insideCompressedPath = true;
01026                     break;
01027                 }
01028                 prevUrl = parentUrl;
01029                 parentUrl = parentUrl.upUrl();
01030             }
01031         }
01032         if (!insideCompressedPath) {
01033             // drop the tar: or zip: protocol since we are not
01034             // inside the compressed path anymore
01035             urlStr = url.path();
01036         }
01037     }
01038 
01039     const KUrl transformedUrl(urlStr);
01040 
01041     // Check whether current history element has the same URL.
01042     // If this is the case, just ignore setting the URL.
01043     const HistoryElem& historyElem = d->m_history[d->m_historyIndex];
01044     const bool isUrlEqual = transformedUrl.equals(historyElem.url(), KUrl::CompareWithoutTrailingSlash) ||
01045                             !transformedUrl.isValid() && (urlStr == historyElem.url().url());
01046     if (isUrlEqual) {
01047         return;
01048     }
01049 
01050     if (d->m_historyIndex > 0) {
01051         // If an URL is set when the history index is not at the end (= 0),
01052         // then clear all previous history elements so that a new history
01053         // tree is started from the current position.
01054         QList<HistoryElem>::iterator begin = d->m_history.begin();
01055         QList<HistoryElem>::iterator end = begin + d->m_historyIndex;
01056         d->m_history.erase(begin, end);
01057         d->m_historyIndex = 0;
01058     }
01059 
01060     Q_ASSERT(d->m_historyIndex == 0);
01061     d->m_history.insert(0, HistoryElem(transformedUrl));
01062 
01063     // Prevent an endless growing of the history: remembering
01064     // the last 100 Urls should be enough...
01065     const int historyMax = 100;
01066     if (d->m_history.size() > historyMax) {
01067         QList<HistoryElem>::iterator begin = d->m_history.begin() + historyMax;
01068         QList<HistoryElem>::iterator end = d->m_history.end();
01069         d->m_history.erase(begin, end);
01070     }
01071 
01072     emit historyChanged();
01073     emit urlChanged(transformedUrl);
01074 
01075     d->updateContent();
01076 
01077     requestActivation();
01078 }
01079 
01080 void KUrlNavigator::requestActivation()
01081 {
01082     setActive(true);
01083 }
01084 
01085 void KUrlNavigator::saveRootUrl(const KUrl& url)
01086 {
01087     HistoryElem& hist = d->m_history[d->m_historyIndex];
01088     hist.setRootUrl(url);
01089 }
01090 
01091 void KUrlNavigator::savePosition(int x, int y)
01092 {
01093     HistoryElem& hist = d->m_history[d->m_historyIndex];
01094     hist.setContentsX(x);
01095     hist.setContentsY(y);
01096 }
01097 
01098 void KUrlNavigator::keyReleaseEvent(QKeyEvent* event)
01099 {
01100     QWidget::keyReleaseEvent(event);
01101     if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
01102         setUrlEditable(false);
01103     }
01104 }
01105 
01106 void KUrlNavigator::mouseReleaseEvent(QMouseEvent* event)
01107 {
01108     if (event->button() == Qt::MidButton) {
01109         QClipboard* clipboard = QApplication::clipboard();
01110         const QMimeData* mimeData = clipboard->mimeData();
01111         if (mimeData->hasText()) {
01112             const QString text = mimeData->text();
01113             setUrl(KUrl(text));
01114         }
01115     }
01116     QWidget::mouseReleaseEvent(event);
01117 }
01118 
01119 void KUrlNavigator::resizeEvent(QResizeEvent* event)
01120 {
01121     QTimer::singleShot(0, this, SLOT(updateButtonVisibility()));
01122     QWidget::resizeEvent(event);
01123 }
01124 
01125 int KUrlNavigator::historySize() const
01126 {
01127     return d->m_history.count();
01128 }
01129 
01130 int KUrlNavigator::historyIndex() const
01131 {
01132     return d->m_historyIndex;
01133 }
01134 
01135 const KUrl& KUrlNavigator::savedRootUrl() const
01136 {
01137     const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01138     return histElem.rootUrl();
01139 }
01140 
01141 QPoint KUrlNavigator::savedPosition() const
01142 {
01143     const HistoryElem& histElem = d->m_history[d->m_historyIndex];
01144     return QPoint(histElem.contentsX(), histElem.contentsY());
01145 }
01146 
01147 KUrlComboBox* KUrlNavigator::editor() const
01148 {
01149     return d->m_pathBox;
01150 }
01151 
01152 void KUrlNavigator::setCustomProtocols(const QStringList &protocols)
01153 {
01154     d->m_customProtocols = protocols;
01155 
01156     d->m_protocols->setCustomProtocols(d->m_customProtocols);
01157 }
01158 
01159 QStringList KUrlNavigator::customProtocols() const
01160 {
01161     return d->m_customProtocols;
01162 }
01163 
01164 void KUrlNavigator::setFocus()
01165 {
01166     if (isUrlEditable()) {
01167         d->m_pathBox->setFocus();
01168     } else if (d->m_host) {
01169         d->m_host->setFocus();
01170     } else {
01171         QWidget::setFocus();
01172     }
01173 }
01174 
01175 #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.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