• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.5 API Reference
  • KDE Home
  • Contact Us
 

KFile

kurlnavigator.cpp
Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Copyright (C) 2006-2010 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 as published by the Free Software Foundation; either              *
00010  * version 2 of the License, or (at your option) any later version.          *
00011  *                                                                           *
00012  * This library is distributed in the hope that it will be useful,           *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00015  * Library General Public License for more details.                          *
00016  *                                                                           *
00017  * You should have received a copy of the GNU Library General Public License *
00018  * along with this library; see the file COPYING.LIB.  If not, write to      *
00019  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,      *
00020  * Boston, MA 02110-1301, USA.                                               *
00021  *****************************************************************************/
00022 
00023 #include "kurlnavigator.h"
00024 
00025 #include "kurlnavigatorplacesselector_p.h"
00026 #include "kurlnavigatorprotocolcombo_p.h"
00027 #include "kurlnavigatordropdownbutton_p.h"
00028 #include "kurlnavigatorbutton_p.h"
00029 #include "kurlnavigatortogglebutton_p.h"
00030 
00031 #include <kfileitem.h>
00032 #include <kfileplacesmodel.h>
00033 #include <kglobalsettings.h>
00034 #include <kicon.h>
00035 #include <klocale.h>
00036 #include <kmenu.h>
00037 #include <kprotocolinfo.h>
00038 #include <kurlcombobox.h>
00039 #include <kurlcompletion.h>
00040 #include <kurifilter.h>
00041 
00042 #include <QtCore/QDir>
00043 #include <QtCore/QLinkedList>
00044 #include <QtCore/QTimer>
00045 #include <QtGui/QApplication>
00046 #include <QtGui/QBoxLayout>
00047 #include <QtGui/QClipboard>
00048 #include <QtGui/QDropEvent>
00049 #include <QtGui/QKeyEvent>
00050 #include <QtGui/QLabel>
00051 #include <QtGui/QPainter>
00052 #include <QtGui/QStyleOption>
00053 
00054 #include <fixx11h.h>
00055 
00056 using namespace KDEPrivate;
00057 
00058 struct LocationData
00059 {
00060     KUrl url;
00061 #ifndef KDE_NO_DEPRECATED
00062     KUrl rootUrl;      // KDE5: remove after the deprecated methods have been removed
00063     QPoint pos;        // KDE5: remove after the deprecated methods have been removed
00064 #endif
00065     QByteArray state;
00066 };
00067 
00068 class KUrlNavigator::Private
00069 {
00070 public:
00071     Private(KUrlNavigator* q, KFilePlacesModel* placesModel);
00072 
00073     void initialize(const KUrl& url);
00074 
00075     void slotReturnPressed();
00076     void slotProtocolChanged(const QString&);
00077     void openPathSelectorMenu();
00078 
00084     void appendWidget(QWidget* widget, int stretch = 0);
00085 
00091     void switchView();
00092 
00094     void dropUrls(const KUrl& destination, QDropEvent* event);
00095 
00101     void slotNavigatorButtonClicked(const KUrl& url, Qt::MouseButton button);
00102 
00103     void openContextMenu();
00104 
00105     void slotPathBoxChanged(const QString& text);
00106 
00107     void updateContent();
00108 
00117     void updateButtons(int startIndex);
00118 
00124     void updateButtonVisibility();
00125 
00129     QString firstButtonText() const;
00130 
00134     KUrl buttonUrl(int index) const;
00135 
00136     void switchToBreadcrumbMode();
00137 
00142     void deleteButtons();
00143 
00151     QString retrievePlacePath() const;
00152 
00157     bool isCompressedPath(const KUrl& path) const;
00158 
00159     void removeTrailingSlash(QString& url) const;
00160 
00168     int adjustedHistoryIndex(int historyIndex) const;
00169 
00170     bool m_editable : 1;
00171     bool m_active : 1;
00172     bool m_showPlacesSelector : 1;
00173     bool m_showFullPath : 1;
00174     int m_historyIndex;
00175 
00176     QHBoxLayout* m_layout;
00177 
00178     QList<LocationData> m_history;
00179     KUrlNavigatorPlacesSelector* m_placesSelector;
00180     KUrlComboBox* m_pathBox;
00181     KUrlNavigatorProtocolCombo* m_protocols;
00182     KUrlNavigatorDropDownButton* m_dropDownButton;
00183     QList<KUrlNavigatorButton*> m_navButtons;
00184     KUrlNavigatorButtonBase* m_toggleEditableMode;
00185     KUrl m_homeUrl;
00186     QStringList m_customProtocols;
00187     KUrlNavigator* q;
00188 };
00189 
00190 
00191 KUrlNavigator::Private::Private(KUrlNavigator* q, KFilePlacesModel* placesModel) :
00192     m_editable(false),
00193     m_active(true),
00194     m_showPlacesSelector(placesModel != 0),
00195     m_showFullPath(false),
00196     m_historyIndex(0),
00197     m_layout(new QHBoxLayout),
00198     m_placesSelector(0),
00199     m_pathBox(0),
00200     m_protocols(0),
00201     m_dropDownButton(0),
00202     m_navButtons(),
00203     m_toggleEditableMode(0),
00204     m_homeUrl(),
00205     m_customProtocols(QStringList()),
00206     q(q)
00207 {
00208     m_layout->setSpacing(0);
00209     m_layout->setMargin(0);
00210 
00211     // initialize the places selector
00212     q->setAutoFillBackground(false);
00213 
00214     if (placesModel != 0) {
00215         m_placesSelector = new KUrlNavigatorPlacesSelector(q, placesModel);
00216         connect(m_placesSelector, SIGNAL(placeActivated(KUrl)),
00217                 q, SLOT(setLocationUrl(KUrl)));
00218 
00219         connect(placesModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
00220                 q, SLOT(updateContent()));
00221         connect(placesModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00222                 q, SLOT(updateContent()));
00223         connect(placesModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
00224                 q, SLOT(updateContent()));
00225     }
00226 
00227     // create protocol combo
00228     m_protocols = new KUrlNavigatorProtocolCombo(QString(), q);
00229     connect(m_protocols, SIGNAL(activated(QString)),
00230             q, SLOT(slotProtocolChanged(QString)));
00231 
00232     // create drop down button for accessing all paths of the URL
00233     m_dropDownButton = new KUrlNavigatorDropDownButton(q);
00234     m_dropDownButton->setForegroundRole(QPalette::WindowText);
00235     m_dropDownButton->installEventFilter(q);
00236     connect(m_dropDownButton, SIGNAL(clicked()),
00237             q, SLOT(openPathSelectorMenu()));
00238 
00239     // initialize the path box of the traditional view
00240     m_pathBox = new KUrlComboBox(KUrlComboBox::Directories, true, q);
00241     m_pathBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
00242     m_pathBox->installEventFilter(q);
00243 
00244     KUrlCompletion* kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
00245     m_pathBox->setCompletionObject(kurlCompletion);
00246     m_pathBox->setAutoDeleteCompletionObject(true);
00247 
00248     connect(m_pathBox, SIGNAL(returnPressed()),
00249             q, SLOT(slotReturnPressed()));
00250     connect(m_pathBox, SIGNAL(urlActivated(KUrl)),
00251             q, SLOT(setLocationUrl(KUrl)));
00252     connect(m_pathBox, SIGNAL(editTextChanged(QString)),
00253             q, SLOT(slotPathBoxChanged(QString)));
00254 
00255     // create toggle button which allows to switch between
00256     // the breadcrumb and traditional view
00257     m_toggleEditableMode = new KUrlNavigatorToggleButton(q);
00258     m_toggleEditableMode->installEventFilter(q);
00259     m_toggleEditableMode->setMinimumWidth(20);
00260     connect(m_toggleEditableMode, SIGNAL(clicked()),
00261             q, SLOT(switchView()));
00262 
00263     if (m_placesSelector != 0) {
00264         m_layout->addWidget(m_placesSelector);
00265     }
00266     m_layout->addWidget(m_protocols);
00267     m_layout->addWidget(m_dropDownButton);
00268     m_layout->addWidget(m_pathBox, 1);
00269     m_layout->addWidget(m_toggleEditableMode);
00270 
00271     q->setContextMenuPolicy(Qt::CustomContextMenu);
00272     connect(q, SIGNAL(customContextMenuRequested(QPoint)),
00273             q, SLOT(openContextMenu()));
00274 }
00275 
00276 void KUrlNavigator::Private::initialize(const KUrl& url)
00277 {
00278     LocationData data;
00279     data.url = url;
00280     m_history.prepend(data);
00281 
00282     q->setLayoutDirection(Qt::LeftToRight);
00283 
00284     const int minHeight = m_pathBox->sizeHint().height();
00285     q->setMinimumHeight(minHeight);
00286 
00287     q->setLayout(m_layout);
00288     q->setMinimumWidth(100);
00289 
00290     updateContent();
00291 }
00292 
00293 void KUrlNavigator::Private::appendWidget(QWidget* widget, int stretch)
00294 {
00295     m_layout->insertWidget(m_layout->count() - 1, widget, stretch);
00296 }
00297 
00298 void KUrlNavigator::Private::slotReturnPressed()
00299 {
00300     // Parts of the following code have been taken
00301     // from the class KateFileSelector located in
00302     // kate/app/katefileselector.hpp of Kate.
00303     // Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
00304     // Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
00305     // Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
00306 
00307     const KUrl typedUrl = q->uncommittedUrl();
00308     QStringList urls = m_pathBox->urls();
00309     urls.removeAll(typedUrl.url());
00310     urls.prepend(typedUrl.url());
00311     m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
00312 
00313     q->setLocationUrl(typedUrl);
00314     // The URL might have been adjusted by KUrlNavigator::setUrl(), hence
00315     // synchronize the result in the path box.
00316     const KUrl currentUrl = q->locationUrl();
00317     m_pathBox->setUrl(currentUrl);
00318 
00319     emit q->returnPressed();
00320 
00321     if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
00322         // Pressing Ctrl+Return automatically switches back to the breadcrumb mode.
00323         // The switch must be done asynchronously, as we are in the context of the
00324         // editor.
00325         QMetaObject::invokeMethod(q, "switchToBreadcrumbMode", Qt::QueuedConnection);
00326     }
00327 }
00328 
00329 void KUrlNavigator::Private::slotProtocolChanged(const QString& protocol)
00330 {
00331     Q_ASSERT(m_editable);
00332 
00333     KUrl url;
00334     url.setProtocol(protocol);
00335     url.setPath((protocol == QLatin1String("file")) ? QLatin1String("/") : QLatin1String("//"));
00336 
00337     m_pathBox->setEditUrl(url);
00338 }
00339 
00340 void KUrlNavigator::Private::openPathSelectorMenu()
00341 {
00342     if (m_navButtons.count() <= 0) {
00343         return;
00344     }
00345 
00346     const KUrl firstVisibleUrl = m_navButtons.first()->url();
00347 
00348     QString spacer;
00349     KMenu* popup = new KMenu(q);
00350     popup->setLayoutDirection(Qt::LeftToRight);
00351 
00352     const QString placePath = retrievePlacePath();
00353     int idx = placePath.count(QLatin1Char('/')); // idx points to the first directory
00354                                                  // after the place path
00355 
00356     const QString path = m_history[m_historyIndex].url.pathOrUrl();
00357     QString dirName = path.section(QLatin1Char('/'), idx, idx);
00358     if (dirName.isEmpty()) {
00359         dirName = QLatin1Char('/');
00360     }
00361     do {
00362         const QString text = spacer + dirName;
00363 
00364         QAction* action = new QAction(text, popup);
00365         const KUrl currentUrl = buttonUrl(idx);
00366         if (currentUrl == firstVisibleUrl) {
00367             popup->addSeparator();
00368         }
00369         action->setData(QVariant(currentUrl.prettyUrl()));
00370         popup->addAction(action);
00371 
00372         ++idx;
00373         spacer.append("  ");
00374         dirName = path.section('/', idx, idx);
00375     } while (!dirName.isEmpty());
00376 
00377     const QPoint pos = q->mapToGlobal(m_dropDownButton->geometry().bottomRight());
00378     const QAction* activatedAction = popup->exec(pos);
00379     if (activatedAction != 0) {
00380         const KUrl url = KUrl(activatedAction->data().toString());
00381         q->setLocationUrl(url);
00382     }
00383 
00384     popup->deleteLater();
00385 }
00386 
00387 void KUrlNavigator::Private::switchView()
00388 {
00389     m_toggleEditableMode->setFocus();
00390     m_editable = !m_editable;
00391     m_toggleEditableMode->setChecked(m_editable);
00392     updateContent();
00393     if (q->isUrlEditable()) {
00394         m_pathBox->setFocus();
00395     }
00396 
00397     emit q->requestActivation();
00398     emit q->editableStateChanged(m_editable);
00399 }
00400 
00401 void KUrlNavigator::Private::dropUrls(const KUrl& destination, QDropEvent* event)
00402 {
00403     const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
00404     if (!urls.isEmpty()) {
00405         emit q->urlsDropped(destination, event);
00406 
00407 #ifndef KDE_NO_DEPRECATED
00408         // KDE5: remove, as the signal has been replaced by
00409         // urlsDropped(const KUrl& destination, QDropEvent* event)
00410         emit q->urlsDropped(urls, destination);
00411 #endif
00412     }
00413 }
00414 
00415 void KUrlNavigator::Private::slotNavigatorButtonClicked(const KUrl& url, Qt::MouseButton button)
00416 {
00417     if (button & Qt::LeftButton) {
00418         q->setLocationUrl(url);
00419     } else if (button & Qt::MidButton) {
00420         emit q->tabRequested(url);
00421     }
00422 }
00423 
00424 void KUrlNavigator::Private::openContextMenu()
00425 {
00426     q->setActive(true);
00427 
00428     KMenu popup(q);
00429 
00430     // provide 'Copy' action, which copies the current URL of
00431     // the URL navigator into the clipboard
00432     QAction* copyAction = popup.addAction(KIcon("edit-copy"), i18n("Copy"));
00433 
00434     // provide 'Paste' action, which copies the current clipboard text
00435     // into the URL navigator
00436     QAction* pasteAction = popup.addAction(KIcon("edit-paste"), i18n("Paste"));
00437     QClipboard* clipboard = QApplication::clipboard();
00438     pasteAction->setEnabled(!clipboard->text().isEmpty());
00439 
00440     popup.addSeparator();
00441 
00442     // provide radiobuttons for toggling between the edit and the navigation mode
00443     QAction* editAction = popup.addAction(i18n("Edit"));
00444     editAction->setCheckable(true);
00445 
00446     QAction* navigateAction = popup.addAction(i18n("Navigate"));
00447     navigateAction->setCheckable(true);
00448 
00449     QActionGroup* modeGroup = new QActionGroup(&popup);
00450     modeGroup->addAction(editAction);
00451     modeGroup->addAction(navigateAction);
00452     if (q->isUrlEditable()) {
00453         editAction->setChecked(true);
00454     } else {
00455         navigateAction->setChecked(true);
00456     }
00457 
00458     popup.addSeparator();
00459 
00460     // allow showing of the full path
00461     QAction* showFullPathAction = popup.addAction(i18n("Show Full Path"));
00462     showFullPathAction->setCheckable(true);
00463     showFullPathAction->setChecked(q->showFullPath());
00464 
00465     QAction* activatedAction = popup.exec(QCursor::pos());
00466     if (activatedAction == copyAction) {
00467         QMimeData* mimeData = new QMimeData();
00468         mimeData->setText(q->locationUrl().pathOrUrl());
00469         clipboard->setMimeData(mimeData);
00470     } else if (activatedAction == pasteAction) {
00471         q->setLocationUrl(KUrl(clipboard->text()));
00472     } else if (activatedAction == editAction) {
00473         q->setUrlEditable(true);
00474     } else if (activatedAction == navigateAction) {
00475         q->setUrlEditable(false);
00476     } else if (activatedAction == showFullPathAction) {
00477         q->setShowFullPath(showFullPathAction->isChecked());
00478     }
00479 }
00480 
00481 void KUrlNavigator::Private::slotPathBoxChanged(const QString& text)
00482 {
00483     if (text.isEmpty()) {
00484         const QString protocol = q->locationUrl().protocol();
00485         m_protocols->setProtocol(protocol);
00486         m_protocols->show();
00487     } else {
00488         m_protocols->hide();
00489     }
00490 }
00491 
00492 void KUrlNavigator::Private::updateContent()
00493 {
00494     const KUrl currentUrl = q->locationUrl();
00495     if (m_placesSelector != 0) {
00496         m_placesSelector->updateSelection(currentUrl);
00497     }
00498 
00499     if (m_editable) {
00500         m_protocols->hide();
00501         m_dropDownButton->hide();
00502 
00503         deleteButtons();
00504         m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
00505         q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
00506 
00507         m_pathBox->show();
00508         m_pathBox->setUrl(currentUrl);
00509     } else {
00510         m_pathBox->hide();
00511 
00512         m_protocols->hide();
00513 
00514         m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
00515         q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
00516 
00517         // Calculate the start index for the directories that should be shown as buttons
00518         // and create the buttons
00519         KUrl placeUrl;
00520         if ((m_placesSelector != 0) && !m_showFullPath) {
00521             placeUrl = m_placesSelector->selectedPlaceUrl();
00522         }
00523 
00524         QString placePath = placeUrl.isValid() ? placeUrl.pathOrUrl() : retrievePlacePath();
00525         removeTrailingSlash(placePath);
00526 
00527         const int startIndex = placePath.count('/');
00528         updateButtons(startIndex);
00529     }
00530 }
00531 
00532 void KUrlNavigator::Private::updateButtons(int startIndex)
00533 {
00534     KUrl currentUrl = q->locationUrl();
00535 
00536     const QString path = currentUrl.pathOrUrl();
00537 
00538     bool createButton = false;
00539     const int oldButtonCount = m_navButtons.count();
00540 
00541     int idx = startIndex;
00542     bool hasNext = true;
00543     do {
00544         createButton = (idx - startIndex >= oldButtonCount);
00545         const bool isFirstButton = (idx == startIndex);
00546         const QString dirName = path.section(QLatin1Char('/'), idx, idx);
00547         hasNext = isFirstButton || !dirName.isEmpty();
00548         if (hasNext) {
00549             KUrlNavigatorButton* button = 0;
00550             if (createButton) {
00551                 button = new KUrlNavigatorButton(buttonUrl(idx), q);
00552                 button->installEventFilter(q);
00553                 button->setForegroundRole(QPalette::WindowText);
00554                 connect(button, SIGNAL(urlsDropped(KUrl,QDropEvent*)),
00555                         q, SLOT(dropUrls(KUrl,QDropEvent*)));
00556                 connect(button, SIGNAL(clicked(KUrl,Qt::MouseButton)),
00557                         q, SLOT(slotNavigatorButtonClicked(KUrl,Qt::MouseButton)));
00558                 connect(button, SIGNAL(finishedTextResolving()),
00559                         q, SLOT(updateButtonVisibility()));
00560                 appendWidget(button);
00561             } else {
00562                 button = m_navButtons[idx - startIndex];
00563                 button->setUrl(buttonUrl(idx));
00564             }
00565 
00566             if (isFirstButton) {
00567                 button->setText(firstButtonText());
00568             }
00569             button->setActive(q->isActive());
00570 
00571             if (createButton) {
00572                 if (!isFirstButton) {
00573                     setTabOrder(m_navButtons.last(), button);
00574                 }
00575                 m_navButtons.append(button);
00576             }
00577 
00578             ++idx;
00579             button->setActiveSubDirectory(path.section(QLatin1Char('/'), idx, idx));
00580         }
00581     } while (hasNext);
00582 
00583     // delete buttons which are not used anymore
00584     const int newButtonCount = idx - startIndex;
00585     if (newButtonCount < oldButtonCount) {
00586         const QList<KUrlNavigatorButton*>::iterator itBegin = m_navButtons.begin() + newButtonCount;
00587         const QList<KUrlNavigatorButton*>::iterator itEnd = m_navButtons.end();
00588         QList<KUrlNavigatorButton*>::iterator it = itBegin;
00589         while (it != itEnd) {
00590             (*it)->hide();
00591             (*it)->deleteLater();
00592             ++it;
00593         }
00594         m_navButtons.erase(itBegin, itEnd);
00595     }
00596 
00597     setTabOrder(m_dropDownButton, m_navButtons.first());
00598     setTabOrder(m_navButtons.last(), m_toggleEditableMode);
00599 
00600     updateButtonVisibility();
00601 }
00602 
00603 void KUrlNavigator::Private::updateButtonVisibility()
00604 {
00605     if (m_editable) {
00606         return;
00607     }
00608 
00609     const int buttonsCount = m_navButtons.count();
00610     if (buttonsCount == 0) {
00611         m_dropDownButton->hide();
00612         return;
00613     }
00614 
00615     // Subtract all widgets from the available width, that must be shown anyway
00616     int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
00617 
00618     if ((m_placesSelector != 0) && m_placesSelector->isVisible()) {
00619         availableWidth -= m_placesSelector->width();
00620     }
00621 
00622     if ((m_protocols != 0) && m_protocols->isVisible()) {
00623         availableWidth -= m_protocols->width();
00624     }
00625 
00626     // Check whether buttons must be hidden at all...
00627     int requiredButtonWidth = 0;
00628     foreach (const KUrlNavigatorButton* button, m_navButtons) {
00629         requiredButtonWidth += button->minimumWidth();
00630     }
00631 
00632     if (requiredButtonWidth > availableWidth) {
00633         // At least one button must be hidden. This implies that the
00634         // drop-down button must get visible, which again decreases the
00635         // available width.
00636         availableWidth -= m_dropDownButton->width();
00637     }
00638 
00639     // Hide buttons...
00640     QList<KUrlNavigatorButton*>::const_iterator it = m_navButtons.constEnd();
00641     const QList<KUrlNavigatorButton*>::const_iterator itBegin = m_navButtons.constBegin();
00642     bool isLastButton = true;
00643     bool hasHiddenButtons = false;
00644 
00645     QLinkedList<KUrlNavigatorButton*> buttonsToShow;
00646     while (it != itBegin) {
00647         --it;
00648         KUrlNavigatorButton* button = (*it);
00649         availableWidth -= button->minimumWidth();
00650         if ((availableWidth <= 0) && !isLastButton) {
00651             button->hide();
00652             hasHiddenButtons = true;
00653         }
00654         else {
00655             // Don't show the button immediately, as setActive()
00656             // might change the size and a relayout gets triggered
00657             // after showing the button. So the showing of all buttons
00658             // is postponed until all buttons have the correct
00659             // activation state.
00660             buttonsToShow.append(button);
00661         }
00662         isLastButton = false;
00663     }
00664 
00665     // All buttons have the correct activation state and
00666     // can be shown now
00667     foreach (KUrlNavigatorButton* button, buttonsToShow) {
00668         button->show();
00669     }
00670 
00671     if (hasHiddenButtons) {
00672         m_dropDownButton->show();
00673     } else {
00674         // Check whether going upwards is possible. If this is the case, show the drop-down button.
00675         KUrl url = m_navButtons.front()->url();
00676         url.adjustPath(KUrl::AddTrailingSlash);
00677         const bool visible = !url.equals(url.upUrl()) && (url.protocol() != "nepomuksearch");
00678         m_dropDownButton->setVisible(visible);
00679     }
00680 }
00681 
00682 QString KUrlNavigator::Private::firstButtonText() const
00683 {
00684     QString text;
00685 
00686     // The first URL navigator button should get the name of the
00687     // place instead of the directory name
00688     if ((m_placesSelector != 0) && !m_showFullPath) {
00689         const KUrl placeUrl = m_placesSelector->selectedPlaceUrl();
00690         text = m_placesSelector->selectedPlaceText();
00691     }
00692 
00693     if (text.isEmpty()) {
00694         const KUrl currentUrl = q->locationUrl();
00695         if (currentUrl.isLocalFile()) {
00696 #ifdef Q_OS_WIN
00697             text = currentUrl.path().length() > 1 ? currentUrl.path().left(2) : QDir::rootPath();
00698 #else
00699             text = m_showFullPath ? QLatin1String("/") : i18n("Custom Path");
00700 #endif
00701         } else {
00702             text = currentUrl.protocol() + QLatin1Char(':');
00703             if (!currentUrl.host().isEmpty()) {
00704                 text += QLatin1Char(' ') + currentUrl.host();
00705             }
00706         }
00707     }
00708 
00709     return text;
00710 }
00711 
00712 KUrl KUrlNavigator::Private::buttonUrl(int index) const
00713 {
00714     if (index < 0) {
00715         index = 0;
00716     }
00717 
00718     // Keep scheme, hostname etc. as this is needed for e. g. browsing
00719     // FTP directories
00720     const KUrl currentUrl = q->locationUrl();
00721     KUrl newUrl = currentUrl;
00722     newUrl.setPath(QString());
00723 
00724     QString pathOrUrl = currentUrl.pathOrUrl();
00725     if (!pathOrUrl.isEmpty()) {
00726         if (index == 0) {
00727             // prevent the last "/" from being stripped
00728             // or we end up with an empty path
00729 #ifdef Q_OS_WIN
00730             pathOrUrl = pathOrUrl.length() > 1 ? pathOrUrl.left(2) : QDir::rootPath();
00731 #else
00732             pathOrUrl = QLatin1String("/");
00733 #endif
00734         } else {
00735             pathOrUrl = pathOrUrl.section('/', 0, index);
00736         }
00737     }
00738 
00739     newUrl.setPath(KUrl(pathOrUrl).path());
00740     return newUrl;
00741 }
00742 
00743 void KUrlNavigator::Private::switchToBreadcrumbMode()
00744 {
00745     q->setUrlEditable(false);
00746 }
00747 
00748 void KUrlNavigator::Private::deleteButtons()
00749 {
00750     foreach (KUrlNavigatorButton* button, m_navButtons) {
00751         button->hide();
00752         button->deleteLater();
00753     }
00754     m_navButtons.clear();
00755 }
00756 
00757 QString KUrlNavigator::Private::retrievePlacePath() const
00758 {
00759     const KUrl currentUrl = q->locationUrl();
00760     const QString path = currentUrl.pathOrUrl();
00761     int idx = path.indexOf(QLatin1String("///"));
00762     if (idx >= 0) {
00763         idx += 3;
00764     } else {
00765         idx = path.indexOf(QLatin1String("//"));
00766         idx = path.indexOf(QLatin1Char('/'), (idx < 0) ? 0 : idx + 2);
00767     }
00768 
00769     QString placePath = (idx < 0) ? path : path.left(idx);
00770     removeTrailingSlash(placePath);
00771     return placePath;
00772 }
00773 
00774 bool KUrlNavigator::Private::isCompressedPath(const KUrl& url) const
00775 {
00776     const KMimeType::Ptr mime = KMimeType::findByPath(url.path(KUrl::RemoveTrailingSlash));
00777     // Note: this list of MIME types depends on the protocols implemented by kio_archive
00778     return  mime->is("application/x-compressed-tar") ||
00779             mime->is("application/x-bzip-compressed-tar") ||
00780             mime->is("application/x-lzma-compressed-tar") ||
00781             mime->is("application/x-xz-compressed-tar") ||
00782             mime->is("application/x-tar") ||
00783             mime->is("application/x-tarz") ||
00784             mime->is("application/x-tzo") || // (not sure KTar supports those?)
00785             mime->is("application/zip") ||
00786             mime->is("application/x-archive");
00787 }
00788 
00789 void KUrlNavigator::Private::removeTrailingSlash(QString& url) const
00790 {
00791     const int length = url.length();
00792     if ((length > 0) && (url.at(length - 1) == QChar('/'))) {
00793         url.remove(length - 1, 1);
00794     }
00795 }
00796 
00797 int KUrlNavigator::Private::adjustedHistoryIndex(int historyIndex) const
00798 {
00799     if (historyIndex < 0) {
00800         historyIndex = m_historyIndex;
00801     } else if (historyIndex >= m_history.size()) {
00802         historyIndex = m_history.size() - 1;
00803         Q_ASSERT(historyIndex >= 0); // m_history.size() must always be > 0
00804     }
00805     return historyIndex;
00806 }
00807 
00808 // ------------------------------------------------------------------------------------------------
00809 
00810 KUrlNavigator::KUrlNavigator(QWidget* parent) :
00811     QWidget(parent),
00812     d(new Private(this, 0))
00813 {
00814     d->initialize(KUrl());
00815 }
00816 
00817 KUrlNavigator::KUrlNavigator(KFilePlacesModel* placesModel,
00818                              const KUrl& url,
00819                              QWidget* parent) :
00820     QWidget(parent),
00821     d(new Private(this, placesModel))
00822 {
00823     d->initialize(url);
00824 }
00825 
00826 KUrlNavigator::~KUrlNavigator()
00827 {
00828     delete d;
00829 }
00830 
00831 KUrl KUrlNavigator::locationUrl(int historyIndex) const
00832 {
00833     historyIndex = d->adjustedHistoryIndex(historyIndex);
00834     return d->m_history[historyIndex].url;
00835 }
00836 
00837 void KUrlNavigator::saveLocationState(const QByteArray& state)
00838 {
00839     d->m_history[d->m_historyIndex].state = state;
00840 }
00841 
00842 QByteArray KUrlNavigator::locationState(int historyIndex) const
00843 {
00844     historyIndex = d->adjustedHistoryIndex(historyIndex);
00845     return d->m_history[historyIndex].state;
00846 }
00847 
00848 bool KUrlNavigator::goBack()
00849 {
00850     const int count = d->m_history.count();
00851     if (d->m_historyIndex < count - 1) {
00852         const KUrl newUrl = locationUrl(d->m_historyIndex + 1);
00853         emit urlAboutToBeChanged(newUrl);
00854 
00855         ++d->m_historyIndex;
00856         d->updateContent();
00857 
00858         emit historyChanged();
00859         emit urlChanged(locationUrl());
00860         return true;
00861     }
00862 
00863     return false;
00864 }
00865 
00866 bool KUrlNavigator::goForward()
00867 {
00868     if (d->m_historyIndex > 0) {
00869         const KUrl newUrl = locationUrl(d->m_historyIndex - 1);
00870         emit urlAboutToBeChanged(newUrl);
00871 
00872         --d->m_historyIndex;
00873         d->updateContent();
00874 
00875         emit historyChanged();
00876         emit urlChanged(locationUrl());
00877         return true;
00878     }
00879 
00880     return false;
00881 }
00882 
00883 bool KUrlNavigator::goUp()
00884 {
00885     const KUrl currentUrl = locationUrl();
00886     const KUrl upUrl = currentUrl.upUrl();
00887     if (upUrl != currentUrl) {
00888         setLocationUrl(upUrl);
00889         return true;
00890     }
00891 
00892     return false;
00893 }
00894 
00895 void KUrlNavigator::goHome()
00896 {
00897     if (d->m_homeUrl.isEmpty() || !d->m_homeUrl.isValid()) {
00898         setLocationUrl(KUrl(QDir::homePath()));
00899     } else {
00900         setLocationUrl(d->m_homeUrl);
00901     }
00902 }
00903 
00904 void KUrlNavigator::setHomeUrl(const KUrl& url)
00905 {
00906     d->m_homeUrl = url;
00907 }
00908 
00909 KUrl KUrlNavigator::homeUrl() const
00910 {
00911     return d->m_homeUrl;
00912 }
00913 
00914 void KUrlNavigator::setUrlEditable(bool editable)
00915 {
00916     if (d->m_editable != editable) {
00917         d->switchView();
00918     }
00919 }
00920 
00921 bool KUrlNavigator::isUrlEditable() const
00922 {
00923     return d->m_editable;
00924 }
00925 
00926 void KUrlNavigator::setShowFullPath(bool show)
00927 {
00928     if (d->m_showFullPath != show) {
00929         d->m_showFullPath = show;
00930         d->updateContent();
00931     }
00932 }
00933 
00934 bool KUrlNavigator::showFullPath() const
00935 {
00936     return d->m_showFullPath;
00937 }
00938 
00939 
00940 void KUrlNavigator::setActive(bool active)
00941 {
00942     if (active != d->m_active) {
00943         d->m_active = active;
00944 
00945         d->m_dropDownButton->setActive(active);
00946         foreach(KUrlNavigatorButton* button, d->m_navButtons) {
00947             button->setActive(active);
00948         }
00949 
00950         update();
00951         if (active) {
00952             emit activated();
00953         }
00954     }
00955 }
00956 
00957 bool KUrlNavigator::isActive() const
00958 {
00959     return d->m_active;
00960 }
00961 
00962 void KUrlNavigator::setPlacesSelectorVisible(bool visible)
00963 {
00964     if (visible == d->m_showPlacesSelector) {
00965         return;
00966     }
00967 
00968     if (visible  && (d->m_placesSelector == 0)) {
00969         // the places selector cannot get visible as no
00970         // places model is available
00971         return;
00972     }
00973 
00974     d->m_showPlacesSelector = visible;
00975     d->m_placesSelector->setVisible(visible);
00976 }
00977 
00978 bool KUrlNavigator::isPlacesSelectorVisible() const
00979 {
00980     return d->m_showPlacesSelector;
00981 }
00982 
00983 KUrl KUrlNavigator::uncommittedUrl() const
00984 {
00985     KUriFilterData filteredData(d->m_pathBox->currentText().trimmed());
00986     filteredData.setCheckForExecutables(false);
00987     if (KUriFilter::self()->filterUri(filteredData, QStringList() << "kshorturifilter" << "kurisearchfilter")) {
00988         return filteredData.uri();
00989     }
00990     else {
00991         return KUrl(filteredData.typedString());
00992     }
00993 }
00994 
00995 void KUrlNavigator::setLocationUrl(const KUrl& newUrl)
00996 {
00997     if (newUrl == locationUrl()) {
00998         return;
00999     }
01000 
01001     KUrl url = newUrl;
01002     url.cleanPath();
01003 
01004     if ((url.protocol() == QLatin1String("tar")) || (url.protocol() == QLatin1String("zip"))) {
01005         // The URL represents a tar- or zip-file. Check whether
01006         // the URL is really part of the tar- or zip-file, otherwise
01007         // replace it by the local path again.
01008         bool insideCompressedPath = d->isCompressedPath(url);
01009         if (!insideCompressedPath) {
01010             KUrl prevUrl = url;
01011             KUrl parentUrl = url.upUrl();
01012             while (parentUrl != prevUrl) {
01013                 if (d->isCompressedPath(parentUrl)) {
01014                     insideCompressedPath = true;
01015                     break;
01016                 }
01017                 prevUrl = parentUrl;
01018                 parentUrl = parentUrl.upUrl();
01019             }
01020         }
01021         if (!insideCompressedPath) {
01022             // drop the tar: or zip: protocol since we are not
01023             // inside the compressed path
01024             url.setProtocol("file");
01025         }
01026     }
01027 
01028     // Check whether current history element has the same URL.
01029     // If this is the case, just ignore setting the URL.
01030     const LocationData& data = d->m_history[d->m_historyIndex];
01031     const bool isUrlEqual = url.equals(locationUrl(), KUrl::CompareWithoutTrailingSlash) ||
01032                             (!url.isValid() && url.equals(data.url, KUrl::CompareWithoutTrailingSlash));
01033     if (isUrlEqual) {
01034         return;
01035     }
01036 
01037     emit urlAboutToBeChanged(url);
01038 
01039     if (d->m_historyIndex > 0) {
01040         // If an URL is set when the history index is not at the end (= 0),
01041         // then clear all previous history elements so that a new history
01042         // tree is started from the current position.
01043         QList<LocationData>::iterator begin = d->m_history.begin();
01044         QList<LocationData>::iterator end = begin + d->m_historyIndex;
01045         d->m_history.erase(begin, end);
01046         d->m_historyIndex = 0;
01047     }
01048 
01049     Q_ASSERT(d->m_historyIndex == 0);
01050     LocationData newData;
01051     newData.url = url;
01052     d->m_history.insert(0, newData);
01053 
01054     // Prevent an endless growing of the history: remembering
01055     // the last 100 Urls should be enough...
01056     const int historyMax = 100;
01057     if (d->m_history.size() > historyMax) {
01058         QList<LocationData>::iterator begin = d->m_history.begin() + historyMax;
01059         QList<LocationData>::iterator end = d->m_history.end();
01060         d->m_history.erase(begin, end);
01061     }
01062 
01063     emit historyChanged();
01064     emit urlChanged(url);
01065 
01066     d->updateContent();
01067 
01068     requestActivation();
01069 }
01070 
01071 void KUrlNavigator::requestActivation()
01072 {
01073     setActive(true);
01074 }
01075 
01076 void KUrlNavigator::setFocus()
01077 {
01078     if (isUrlEditable()) {
01079         d->m_pathBox->setFocus();
01080     } else {
01081         QWidget::setFocus();
01082     }
01083 }
01084 
01085 #ifndef KDE_NO_DEPRECATED
01086 void KUrlNavigator::setUrl(const KUrl& url)
01087 {
01088     // deprecated
01089     setLocationUrl(url);
01090 }
01091 #endif
01092 
01093 #ifndef KDE_NO_DEPRECATED
01094 void KUrlNavigator::saveRootUrl(const KUrl& url)
01095 {
01096     // deprecated
01097     d->m_history[d->m_historyIndex].rootUrl = url;
01098 }
01099 #endif
01100 
01101 #ifndef KDE_NO_DEPRECATED
01102 void KUrlNavigator::savePosition(int x, int y)
01103 {
01104     // deprecated
01105     d->m_history[d->m_historyIndex].pos = QPoint(x, y);
01106 }
01107 #endif
01108 
01109 void KUrlNavigator::keyPressEvent(QKeyEvent* event)
01110 {
01111     if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
01112         setUrlEditable(false);
01113     } else {
01114         QWidget::keyPressEvent(event);
01115     }
01116 }
01117 
01118 void KUrlNavigator::keyReleaseEvent(QKeyEvent* event)
01119 {
01120     QWidget::keyReleaseEvent(event);
01121 }
01122 
01123 void KUrlNavigator::mouseReleaseEvent(QMouseEvent* event)
01124 {
01125     if (event->button() == Qt::MidButton) {
01126         const QRect bounds = d->m_toggleEditableMode->geometry();
01127         if (bounds.contains(event->pos())) {
01128             // The middle mouse button has been clicked above the
01129             // toggle-editable-mode-button. Paste the clipboard content
01130             // as location URL.
01131             QClipboard* clipboard = QApplication::clipboard();
01132             const QMimeData* mimeData = clipboard->mimeData();
01133             if (mimeData->hasText()) {
01134                 const QString text = mimeData->text();
01135                 setLocationUrl(KUrl(text));
01136             }
01137         }
01138     }
01139     QWidget::mouseReleaseEvent(event);
01140 }
01141 
01142 void KUrlNavigator::resizeEvent(QResizeEvent* event)
01143 {
01144     QTimer::singleShot(0, this, SLOT(updateButtonVisibility()));
01145     QWidget::resizeEvent(event);
01146 }
01147 
01148 void KUrlNavigator::wheelEvent(QWheelEvent* event)
01149 {
01150     setActive(true);
01151     QWidget::wheelEvent(event);
01152 }
01153 
01154 bool KUrlNavigator::eventFilter(QObject* watched, QEvent* event)
01155 {
01156     switch (event->type()) {
01157     case QEvent::FocusIn:
01158         if (watched == d->m_pathBox) {
01159             requestActivation();
01160             setFocus();
01161         }
01162         foreach (KUrlNavigatorButton* button, d->m_navButtons) {
01163             button->setShowMnemonic(true);
01164         }
01165         break;
01166 
01167     case QEvent::FocusOut:
01168         foreach (KUrlNavigatorButton* button, d->m_navButtons) {
01169             button->setShowMnemonic(false);
01170         }
01171         break;
01172 
01173     default:
01174         break;
01175     }
01176 
01177     return QWidget::eventFilter(watched, event);
01178 }
01179 
01180 int KUrlNavigator::historySize() const
01181 {
01182     return d->m_history.count();
01183 }
01184 
01185 int KUrlNavigator::historyIndex() const
01186 {
01187     return d->m_historyIndex;
01188 }
01189 
01190 KUrlComboBox* KUrlNavigator::editor() const
01191 {
01192     return d->m_pathBox;
01193 }
01194 
01195 void KUrlNavigator::setCustomProtocols(const QStringList &protocols)
01196 {
01197     d->m_customProtocols = protocols;
01198     d->m_protocols->setCustomProtocols(d->m_customProtocols);
01199 }
01200 
01201 QStringList KUrlNavigator::customProtocols() const
01202 {
01203     return d->m_customProtocols;
01204 }
01205 
01206 #ifndef KDE_NO_DEPRECATED
01207 const KUrl& KUrlNavigator::url() const
01208 {
01209     // deprecated
01210 
01211     // Workaround required because of flawed interface ('const KUrl&' is returned
01212     // instead of 'KUrl'): remember the URL to prevent a dangling pointer
01213     static KUrl url;
01214     url = locationUrl();
01215     return url;
01216 }
01217 #endif
01218 
01219 #ifndef KDE_NO_DEPRECATED
01220 KUrl KUrlNavigator::url(int index) const
01221 {
01222     // deprecated
01223     return d->buttonUrl(index);
01224 }
01225 #endif
01226 
01227 #ifndef KDE_NO_DEPRECATED
01228 KUrl KUrlNavigator::historyUrl(int historyIndex) const
01229 {
01230     // deprecated
01231     return locationUrl(historyIndex);
01232 }
01233 #endif
01234 
01235 #ifndef KDE_NO_DEPRECATED
01236 const KUrl& KUrlNavigator::savedRootUrl() const
01237 {
01238     // deprecated
01239 
01240     // Workaround required because of flawed interface ('const KUrl&' is returned
01241     // instead of 'KUrl'): remember the root URL to prevent a dangling pointer
01242     static KUrl rootUrl;
01243     rootUrl = d->m_history[d->m_historyIndex].rootUrl;
01244     return rootUrl;
01245 }
01246 #endif
01247 
01248 #ifndef KDE_NO_DEPRECATED
01249 QPoint KUrlNavigator::savedPosition() const
01250 {
01251     // deprecated
01252     return d->m_history[d->m_historyIndex].pos;
01253 }
01254 #endif
01255 
01256 #ifndef KDE_NO_DEPRECATED
01257 void KUrlNavigator::setHomeUrl(const QString& homeUrl)
01258 {
01259     // deprecated
01260     setLocationUrl(KUrl(homeUrl));
01261 }
01262 #endif
01263 
01264 #include "kurlnavigator.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:40:58 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KFile

Skip menu "KFile"
  • Main Page
  • Namespace List
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal