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