File indexing completed on 2023-09-24 04:08:55
0001 /* 0002 SPDX-FileCopyrightText: 2006-2010 Peter Penz <peter.penz@gmx.at> 0003 SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org> 0004 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org> 0005 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "kurlnavigator.h" 0011 #include "kcoreurlnavigator.h" 0012 0013 #include "../utils_p.h" 0014 #include "kurlnavigatorbutton_p.h" 0015 #include "kurlnavigatordropdownbutton_p.h" 0016 #include "kurlnavigatorpathselectoreventfilter_p.h" 0017 #include "kurlnavigatorplacesselector_p.h" 0018 #include "kurlnavigatorprotocolcombo_p.h" 0019 #include "kurlnavigatortogglebutton_p.h" 0020 0021 #include <KIO/StatJob> 0022 #include <KLocalizedString> 0023 #include <kfileitem.h> 0024 #include <kfileplacesmodel.h> 0025 #include <kprotocolinfo.h> 0026 #include <kurifilter.h> 0027 #include <kurlcombobox.h> 0028 #include <kurlcompletion.h> 0029 0030 #include <QActionGroup> 0031 #include <QApplication> 0032 #include <QClipboard> 0033 #include <QDir> 0034 #include <QDropEvent> 0035 #include <QHBoxLayout> 0036 #include <QKeyEvent> 0037 #include <QMenu> 0038 #include <QMetaMethod> 0039 #include <QMimeData> 0040 #include <QMimeDatabase> 0041 #include <QTimer> 0042 #include <QUrlQuery> 0043 0044 #include <algorithm> 0045 #include <numeric> 0046 0047 using namespace KDEPrivate; 0048 0049 struct KUrlNavigatorData { 0050 QUrl rootUrl; // KF6: remove after the deprecated methods have been removed 0051 QPoint pos; // KF6: remove after the deprecated methods have been removed 0052 QByteArray state; 0053 }; 0054 Q_DECLARE_METATYPE(KUrlNavigatorData) 0055 0056 class KUrlNavigatorPrivate 0057 { 0058 public: 0059 KUrlNavigatorPrivate(const QUrl &url, KUrlNavigator *qq, KFilePlacesModel *placesModel); 0060 0061 ~KUrlNavigatorPrivate() 0062 { 0063 m_dropDownButton->removeEventFilter(q); 0064 m_pathBox->removeEventFilter(q); 0065 m_toggleEditableMode->removeEventFilter(q); 0066 0067 for (KUrlNavigatorButton *button : std::as_const(m_navButtons)) { 0068 button->removeEventFilter(q); 0069 } 0070 } 0071 0072 /** Applies the edited URL in m_pathBox to the URL navigator */ 0073 void applyUncommittedUrl(); 0074 void slotApplyUrl(QUrl url); 0075 // Returns true if "text" matched a URI filter (i.e. was fitlered), 0076 // otherwise returns false 0077 bool slotCheckFilters(const QString &text); 0078 0079 void slotReturnPressed(); 0080 void slotProtocolChanged(const QString &); 0081 void openPathSelectorMenu(); 0082 0083 /** 0084 * Appends the widget at the end of the URL navigator. It is assured 0085 * that the filler widget remains as last widget to fill the remaining 0086 * width. 0087 */ 0088 void appendWidget(QWidget *widget, int stretch = 0); 0089 0090 /** 0091 * This slot is connected to the clicked signal of the navigation bar button. It calls switchView(). 0092 * Moreover, if switching from "editable" mode to the breadcrumb view, it calls applyUncommittedUrl(). 0093 */ 0094 void slotToggleEditableButtonPressed(); 0095 0096 /** 0097 * Switches the navigation bar between the breadcrumb view and the 0098 * traditional view (see setUrlEditable()). 0099 */ 0100 void switchView(); 0101 0102 /** Emits the signal urlsDropped(). */ 0103 void dropUrls(const QUrl &destination, QDropEvent *event, KUrlNavigatorButton *dropButton); 0104 0105 /** 0106 * Is invoked when a navigator button has been clicked. 0107 * Different combinations of mouse clicks and keyboard modifiers have different effects on how 0108 * the url is opened. The behaviours are the following: 0109 * - shift+middle-click or ctrl+shift+left-click => activeTabRequested() signal is emitted 0110 * - ctrl+left-click or middle-click => tabRequested() signal is emitted 0111 * - shift+left-click => newWindowRequested() signal is emitted 0112 * - left-click => open the new url in-place 0113 */ 0114 void slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers); 0115 0116 void openContextMenu(const QPoint &p); 0117 0118 void slotPathBoxChanged(const QString &text); 0119 0120 void updateContent(); 0121 0122 /** 0123 * Updates all buttons to have one button for each part of the 0124 * current URL. Existing buttons, which are available by m_navButtons, 0125 * are reused if possible. If the URL is longer, new buttons will be 0126 * created, if the URL is shorter, the remaining buttons will be deleted. 0127 * @param startIndex Start index of URL part (/), where the buttons 0128 * should be created for each following part. 0129 */ 0130 void updateButtons(int startIndex); 0131 0132 /** 0133 * Updates the visibility state of all buttons describing the URL. If the 0134 * width of the URL navigator is too small, the buttons representing the upper 0135 * paths of the URL will be hidden and moved to a drop down menu. 0136 */ 0137 void updateButtonVisibility(); 0138 0139 /** 0140 * @return Text for the first button of the URL navigator. 0141 */ 0142 QString firstButtonText() const; 0143 0144 /** 0145 * Returns the URL that should be applied for the button with the index \a index. 0146 */ 0147 QUrl buttonUrl(int index) const; 0148 0149 void switchToBreadcrumbMode(); 0150 0151 /** 0152 * Deletes all URL navigator buttons. m_navButtons is 0153 * empty after this operation. 0154 */ 0155 void deleteButtons(); 0156 0157 /** 0158 * Retrieves the place url for the current url. 0159 * E. g. for the path "fish://root@192.168.0.2/var/lib" the string 0160 * "fish://root@192.168.0.2" will be returned, which leads to the 0161 * navigation indication 'Custom Path > var > lib". For e. g. 0162 * "settings:///System/" the path "settings://" will be returned. 0163 */ 0164 QUrl retrievePlaceUrl() const; 0165 0166 KUrlNavigator *const q; 0167 0168 QHBoxLayout *m_layout = new QHBoxLayout(q); 0169 KCoreUrlNavigator *m_coreUrlNavigator = nullptr; 0170 QList<KUrlNavigatorButton *> m_navButtons; 0171 QStringList m_customProtocols; 0172 QUrl m_homeUrl; 0173 KUrlNavigatorPlacesSelector *m_placesSelector = nullptr; 0174 KUrlComboBox *m_pathBox = nullptr; 0175 KUrlNavigatorProtocolCombo *m_protocols = nullptr; 0176 KUrlNavigatorDropDownButton *m_dropDownButton = nullptr; 0177 KUrlNavigatorButtonBase *m_toggleEditableMode = nullptr; 0178 QWidget *m_dropWidget = nullptr; 0179 0180 bool m_editable = false; 0181 bool m_active = true; 0182 bool m_showPlacesSelector = false; 0183 bool m_showFullPath = false; 0184 0185 struct { 0186 bool showHidden = false; 0187 bool sortHiddenLast = false; 0188 } m_subfolderOptions; 0189 }; 0190 0191 KUrlNavigatorPrivate::KUrlNavigatorPrivate(const QUrl &url, KUrlNavigator *qq, KFilePlacesModel *placesModel) 0192 : q(qq) 0193 , m_coreUrlNavigator(new KCoreUrlNavigator(url, qq)) 0194 , m_showPlacesSelector(placesModel != nullptr) 0195 { 0196 m_layout->setSpacing(0); 0197 m_layout->setContentsMargins(0, 0, 0, 0); 0198 0199 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::currentLocationUrlChanged, q, [this]() { 0200 Q_EMIT q->urlChanged(m_coreUrlNavigator->currentLocationUrl()); 0201 }); 0202 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::currentUrlAboutToChange, q, [this](const QUrl &url) { 0203 Q_EMIT q->urlAboutToBeChanged(url); 0204 }); 0205 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historySizeChanged, q, [this]() { 0206 Q_EMIT q->historyChanged(); 0207 }); 0208 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historyIndexChanged, q, [this]() { 0209 Q_EMIT q->historyChanged(); 0210 }); 0211 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historyChanged, q, [this]() { 0212 Q_EMIT q->historyChanged(); 0213 }); 0214 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::urlSelectionRequested, q, [this](const QUrl &url) { 0215 Q_EMIT q->urlSelectionRequested(url); 0216 }); 0217 0218 // initialize the places selector 0219 q->setAutoFillBackground(false); 0220 0221 if (placesModel != nullptr) { 0222 m_placesSelector = new KUrlNavigatorPlacesSelector(q, placesModel); 0223 q->connect(m_placesSelector, &KUrlNavigatorPlacesSelector::placeActivated, q, &KUrlNavigator::setLocationUrl); 0224 q->connect(m_placesSelector, &KUrlNavigatorPlacesSelector::tabRequested, q, &KUrlNavigator::tabRequested); 0225 0226 auto updateContentFunc = [this]() { 0227 updateContent(); 0228 }; 0229 q->connect(placesModel, &KFilePlacesModel::rowsInserted, q, updateContentFunc); 0230 q->connect(placesModel, &KFilePlacesModel::rowsRemoved, q, updateContentFunc); 0231 q->connect(placesModel, &KFilePlacesModel::dataChanged, q, updateContentFunc); 0232 } 0233 0234 // create protocol combo 0235 m_protocols = new KUrlNavigatorProtocolCombo(QString(), q); 0236 q->connect(m_protocols, &KUrlNavigatorProtocolCombo::activated, q, [this](const QString &protocol) { 0237 slotProtocolChanged(protocol); 0238 }); 0239 0240 // create drop down button for accessing all paths of the URL 0241 m_dropDownButton = new KUrlNavigatorDropDownButton(q); 0242 m_dropDownButton->setForegroundRole(QPalette::WindowText); 0243 m_dropDownButton->installEventFilter(q); 0244 q->connect(m_dropDownButton, &KUrlNavigatorDropDownButton::clicked, q, [this]() { 0245 openPathSelectorMenu(); 0246 }); 0247 0248 // initialize the path box of the traditional view 0249 m_pathBox = new KUrlComboBox(KUrlComboBox::Directories, true, q); 0250 m_pathBox->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow); 0251 m_pathBox->installEventFilter(q); 0252 0253 KUrlCompletion *kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion); 0254 m_pathBox->setCompletionObject(kurlCompletion); 0255 m_pathBox->setAutoDeleteCompletionObject(true); 0256 0257 // TODO KF6: remove this QOverload, only KUrlComboBox::returnPressed(const QString &) will remain 0258 q->connect(m_pathBox, qOverload<const QString &>(&KUrlComboBox::returnPressed), q, [this]() { 0259 slotReturnPressed(); 0260 }); 0261 q->connect(m_pathBox, &KUrlComboBox::urlActivated, q, &KUrlNavigator::setLocationUrl); 0262 q->connect(m_pathBox, &QComboBox::editTextChanged, q, [this](const QString &text) { 0263 slotPathBoxChanged(text); 0264 }); 0265 0266 // create toggle button which allows to switch between 0267 // the breadcrumb and traditional view 0268 m_toggleEditableMode = new KUrlNavigatorToggleButton(q); 0269 m_toggleEditableMode->installEventFilter(q); 0270 m_toggleEditableMode->setMinimumWidth(20); 0271 q->connect(m_toggleEditableMode, &KUrlNavigatorToggleButton::clicked, q, [this]() { 0272 slotToggleEditableButtonPressed(); 0273 }); 0274 0275 if (m_placesSelector != nullptr) { 0276 m_layout->addWidget(m_placesSelector); 0277 } 0278 m_layout->addWidget(m_protocols); 0279 m_layout->addWidget(m_dropDownButton); 0280 m_layout->addWidget(m_pathBox, 1); 0281 m_layout->addWidget(m_toggleEditableMode); 0282 0283 q->setContextMenuPolicy(Qt::CustomContextMenu); 0284 q->connect(q, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) { 0285 openContextMenu(pos); 0286 }); 0287 } 0288 0289 void KUrlNavigatorPrivate::appendWidget(QWidget *widget, int stretch) 0290 { 0291 m_layout->insertWidget(m_layout->count() - 1, widget, stretch); 0292 } 0293 0294 void KUrlNavigatorPrivate::slotApplyUrl(QUrl url) 0295 { 0296 // Parts of the following code have been taken from the class KateFileSelector 0297 // located in kate/app/katefileselector.hpp of Kate. 0298 // SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org> 0299 // SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org> 0300 // SPDX-FileCopyrightText: 2001 Anders Lund <anders.lund@lund.tdcadsl.dk> 0301 0302 // For example "desktop:/" _not_ "desktop:", see the comment in slotProtocolChanged() 0303 if (!url.isEmpty() && url.path().isEmpty() && KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) { 0304 url.setPath(QStringLiteral("/")); 0305 } 0306 0307 const auto urlStr = url.toString(); 0308 QStringList urls = m_pathBox->urls(); 0309 urls.removeAll(urlStr); 0310 urls.prepend(urlStr); 0311 m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom); 0312 0313 q->setLocationUrl(url); 0314 // The URL might have been adjusted by KUrlNavigator::setUrl(), hence 0315 // synchronize the result in the path box. 0316 m_pathBox->setUrl(q->locationUrl()); 0317 } 0318 0319 bool KUrlNavigatorPrivate::slotCheckFilters(const QString &text) 0320 { 0321 KUriFilterData filteredData(text); 0322 filteredData.setCheckForExecutables(false); 0323 // Using kshorturifilter to fix up e.g. "ftp.kde.org" ---> "ftp://ftp.kde.org" 0324 const auto filtersList = QStringList{QStringLiteral("kshorturifilter")}; 0325 const bool wasFiltered = KUriFilter::self()->filterUri(filteredData, filtersList); 0326 if (wasFiltered) { 0327 slotApplyUrl(filteredData.uri()); // The text was filtered 0328 } 0329 return wasFiltered; 0330 } 0331 0332 void KUrlNavigatorPrivate::applyUncommittedUrl() 0333 { 0334 const QString text = m_pathBox->currentText().trimmed(); 0335 QUrl url = q->locationUrl(); 0336 0337 // Using the stat job below, check if the url and text match a local dir; but first 0338 // handle a special case where "url" is empty in the unittests which use 0339 // KUrlNavigator::setLocationUrl(QUrl()); in practice (e.g. in Dolphin, or KFileWidget), 0340 // locationUrl() is never empty 0341 if (url.isEmpty() && !text.isEmpty()) { 0342 if (slotCheckFilters(text)) { 0343 return; 0344 } 0345 } 0346 0347 // Treat absolute paths as absolute paths. 0348 // Relative paths get appended to the current path. 0349 if (text.startsWith(QLatin1Char('/'))) { 0350 url.setPath(text); 0351 } else { 0352 url.setPath(Utils::concatPaths(url.path(), text)); 0353 } 0354 0355 // Dirs and symlinks to dirs 0356 constexpr auto details = KIO::StatBasic | KIO::StatResolveSymlink; 0357 auto *job = KIO::statDetails(url, KIO::StatJob::DestinationSide, details, KIO::HideProgressInfo); 0358 q->connect(job, &KJob::result, q, [this, job, text]() { 0359 // If there is a dir matching "text" relative to the current url, use that, e.g.: 0360 // - typing "bar" while at "/path/to/foo" ---> "/path/to/foo/bar/" 0361 // - typing ".config" while at "/home/foo" ---> "/home/foo/.config" 0362 if (!job->error() && job->statResult().isDir()) { 0363 slotApplyUrl(job->url()); 0364 return; 0365 } 0366 0367 // Check if text matches a URI filter 0368 if (slotCheckFilters(text)) { 0369 return; 0370 } 0371 0372 // ... otherwise fallback to whatever QUrl::fromUserInput() returns 0373 slotApplyUrl(QUrl::fromUserInput(text)); 0374 }); 0375 } 0376 0377 void KUrlNavigatorPrivate::slotReturnPressed() 0378 { 0379 applyUncommittedUrl(); 0380 0381 Q_EMIT q->returnPressed(); 0382 0383 if (QApplication::keyboardModifiers() & Qt::ControlModifier) { 0384 // Pressing Ctrl+Return automatically switches back to the breadcrumb mode. 0385 // The switch must be done asynchronously, as we are in the context of the 0386 // editor. 0387 auto switchModeFunc = [this]() { 0388 switchToBreadcrumbMode(); 0389 }; 0390 QMetaObject::invokeMethod(q, switchModeFunc, Qt::QueuedConnection); 0391 } 0392 } 0393 0394 void KUrlNavigatorPrivate::slotProtocolChanged(const QString &protocol) 0395 { 0396 Q_ASSERT(m_editable); 0397 0398 QUrl url; 0399 url.setScheme(protocol); 0400 if (KProtocolInfo::protocolClass(protocol) == QLatin1String(":local")) { 0401 // E.g. "file:/" or "desktop:/", _not_ "file:" or "desktop:" respectively. 0402 // This is the more expected behaviour, "file:somedir" treats somedir as 0403 // a path relative to current dir; file:/somedir is an absolute path to /somedir. 0404 url.setPath(QStringLiteral("/")); 0405 } else { 0406 // With no authority set we'll get e.g. "ftp:" instead of "ftp://". 0407 // We want the latter, so let's set an empty authority. 0408 url.setAuthority(QString()); 0409 } 0410 0411 m_pathBox->setEditUrl(url); 0412 } 0413 0414 void KUrlNavigatorPrivate::openPathSelectorMenu() 0415 { 0416 if (m_navButtons.count() <= 0) { 0417 return; 0418 } 0419 0420 const QUrl firstVisibleUrl = m_navButtons.constFirst()->url(); 0421 0422 QString spacer; 0423 QPointer<QMenu> popup = new QMenu(q); 0424 0425 auto *popupFilter = new KUrlNavigatorPathSelectorEventFilter(popup.data()); 0426 q->connect(popupFilter, &KUrlNavigatorPathSelectorEventFilter::tabRequested, q, &KUrlNavigator::tabRequested); 0427 popup->installEventFilter(popupFilter); 0428 0429 const QUrl placeUrl = retrievePlaceUrl(); 0430 int idx = placeUrl.path().count(QLatin1Char('/')); // idx points to the first directory 0431 // after the place path 0432 0433 const QString path = m_coreUrlNavigator->locationUrl(m_coreUrlNavigator->historyIndex()).path(); 0434 QString dirName = path.section(QLatin1Char('/'), idx, idx); 0435 if (dirName.isEmpty()) { 0436 if (placeUrl.isLocalFile()) { 0437 dirName = QStringLiteral("/"); 0438 } else { 0439 dirName = placeUrl.toDisplayString(); 0440 } 0441 } 0442 do { 0443 const QString text = spacer + dirName; 0444 0445 QAction *action = new QAction(text, popup); 0446 const QUrl currentUrl = buttonUrl(idx); 0447 if (currentUrl == firstVisibleUrl) { 0448 popup->addSeparator(); 0449 } 0450 action->setData(QVariant(currentUrl.toString())); 0451 popup->addAction(action); 0452 0453 ++idx; 0454 spacer.append(QLatin1String(" ")); 0455 dirName = path.section(QLatin1Char('/'), idx, idx); 0456 } while (!dirName.isEmpty()); 0457 0458 const QPoint pos = q->mapToGlobal(m_dropDownButton->geometry().bottomRight()); 0459 const QAction *activatedAction = popup->exec(pos); 0460 if (activatedAction != nullptr) { 0461 const QUrl url(activatedAction->data().toString()); 0462 q->setLocationUrl(url); 0463 } 0464 0465 // Delete the menu, unless it has been deleted in its own nested event loop already. 0466 if (popup) { 0467 popup->deleteLater(); 0468 } 0469 } 0470 0471 void KUrlNavigatorPrivate::slotToggleEditableButtonPressed() 0472 { 0473 if (m_editable) { 0474 applyUncommittedUrl(); 0475 } 0476 0477 switchView(); 0478 } 0479 0480 void KUrlNavigatorPrivate::switchView() 0481 { 0482 m_toggleEditableMode->setFocus(); 0483 m_editable = !m_editable; 0484 m_toggleEditableMode->setChecked(m_editable); 0485 updateContent(); 0486 if (q->isUrlEditable()) { 0487 m_pathBox->setFocus(); 0488 } 0489 0490 q->requestActivation(); 0491 Q_EMIT q->editableStateChanged(m_editable); 0492 } 0493 0494 void KUrlNavigatorPrivate::dropUrls(const QUrl &destination, QDropEvent *event, KUrlNavigatorButton *dropButton) 0495 { 0496 if (event->mimeData()->hasUrls()) { 0497 m_dropWidget = qobject_cast<QWidget *>(dropButton); 0498 Q_EMIT q->urlsDropped(destination, event); 0499 } 0500 } 0501 0502 void KUrlNavigatorPrivate::slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) 0503 { 0504 if ((button & Qt::MiddleButton && modifiers & Qt::ShiftModifier) || (button & Qt::LeftButton && modifiers & (Qt::ControlModifier | Qt::ShiftModifier))) { 0505 Q_EMIT q->activeTabRequested(url); 0506 } else if (button & Qt::MiddleButton || (button & Qt::LeftButton && modifiers & Qt::ControlModifier)) { 0507 Q_EMIT q->tabRequested(url); 0508 } else if (button & Qt::LeftButton && modifiers & Qt::ShiftModifier) { 0509 Q_EMIT q->newWindowRequested(url); 0510 } else if (button & Qt::LeftButton) { 0511 q->setLocationUrl(url); 0512 } 0513 } 0514 0515 void KUrlNavigatorPrivate::openContextMenu(const QPoint &p) 0516 { 0517 q->setActive(true); 0518 0519 QPointer<QMenu> popup = new QMenu(q); 0520 0521 // provide 'Copy' action, which copies the current URL of 0522 // the URL navigator into the clipboard 0523 QAction *copyAction = popup->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy")); 0524 0525 // provide 'Paste' action, which copies the current clipboard text 0526 // into the URL navigator 0527 QAction *pasteAction = popup->addAction(QIcon::fromTheme(QStringLiteral("edit-paste")), i18n("Paste")); 0528 QClipboard *clipboard = QApplication::clipboard(); 0529 pasteAction->setEnabled(!clipboard->text().isEmpty()); 0530 0531 popup->addSeparator(); 0532 0533 // We are checking whether the signal is connected because it's odd to have a tab entry even 0534 // if it's not supported, like in the case of the open dialog 0535 const bool isTabSignal = q->isSignalConnected(QMetaMethod::fromSignal(&KUrlNavigator::tabRequested)); 0536 const bool isWindowSignal = q->isSignalConnected(QMetaMethod::fromSignal(&KUrlNavigator::newWindowRequested)); 0537 if (isTabSignal || isWindowSignal) { 0538 auto it = std::find_if(m_navButtons.cbegin(), m_navButtons.cend(), [&p](const KUrlNavigatorButton *button) { 0539 return button->geometry().contains(p); 0540 }); 0541 if (it != m_navButtons.cend()) { 0542 const auto *button = *it; 0543 const QUrl url = button->url(); 0544 const QString text = button->text(); 0545 0546 if (isTabSignal) { 0547 QAction *openInTab = popup->addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@item:inmenu", "Open \"%1\" in New Tab", text)); 0548 q->connect(openInTab, &QAction::triggered, q, [this, url]() { 0549 Q_EMIT q->tabRequested(url); 0550 }); 0551 } 0552 0553 if (isWindowSignal) { 0554 QAction *openInWindow = 0555 popup->addAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("@item:inmenu", "Open \"%1\" in New Window", text)); 0556 q->connect(openInWindow, &QAction::triggered, q, [this, url]() { 0557 Q_EMIT q->newWindowRequested(url); 0558 }); 0559 } 0560 } 0561 } 0562 0563 // provide radiobuttons for toggling between the edit and the navigation mode 0564 QAction *editAction = popup->addAction(i18n("Edit")); 0565 editAction->setCheckable(true); 0566 0567 QAction *navigateAction = popup->addAction(i18n("Navigate")); 0568 navigateAction->setCheckable(true); 0569 0570 QActionGroup *modeGroup = new QActionGroup(popup); 0571 modeGroup->addAction(editAction); 0572 modeGroup->addAction(navigateAction); 0573 if (q->isUrlEditable()) { 0574 editAction->setChecked(true); 0575 } else { 0576 navigateAction->setChecked(true); 0577 } 0578 0579 popup->addSeparator(); 0580 0581 // allow showing of the full path 0582 QAction *showFullPathAction = popup->addAction(i18n("Show Full Path")); 0583 showFullPathAction->setCheckable(true); 0584 showFullPathAction->setChecked(q->showFullPath()); 0585 0586 QAction *activatedAction = popup->exec(QCursor::pos()); 0587 if (activatedAction == copyAction) { 0588 QMimeData *mimeData = new QMimeData(); 0589 mimeData->setText(q->locationUrl().toDisplayString(QUrl::PreferLocalFile)); 0590 clipboard->setMimeData(mimeData); 0591 } else if (activatedAction == pasteAction) { 0592 q->setLocationUrl(QUrl::fromUserInput(clipboard->text())); 0593 } else if (activatedAction == editAction) { 0594 q->setUrlEditable(true); 0595 } else if (activatedAction == navigateAction) { 0596 q->setUrlEditable(false); 0597 } else if (activatedAction == showFullPathAction) { 0598 q->setShowFullPath(showFullPathAction->isChecked()); 0599 } 0600 0601 // Delete the menu, unless it has been deleted in its own nested event loop already. 0602 if (popup) { 0603 popup->deleteLater(); 0604 } 0605 } 0606 0607 void KUrlNavigatorPrivate::slotPathBoxChanged(const QString &text) 0608 { 0609 if (text.isEmpty()) { 0610 const QString protocol = q->locationUrl().scheme(); 0611 m_protocols->setProtocol(protocol); 0612 if (m_customProtocols.count() != 1) { 0613 m_protocols->show(); 0614 } 0615 } else { 0616 m_protocols->hide(); 0617 } 0618 } 0619 0620 void KUrlNavigatorPrivate::updateContent() 0621 { 0622 const QUrl currentUrl = q->locationUrl(); 0623 if (m_placesSelector != nullptr) { 0624 m_placesSelector->updateSelection(currentUrl); 0625 } 0626 0627 if (m_editable) { 0628 m_protocols->hide(); 0629 m_dropDownButton->hide(); 0630 0631 deleteButtons(); 0632 m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); 0633 q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); 0634 0635 m_pathBox->show(); 0636 m_pathBox->setUrl(currentUrl); 0637 } else { 0638 m_pathBox->hide(); 0639 0640 m_protocols->hide(); 0641 0642 m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); 0643 q->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 0644 0645 // Calculate the start index for the directories that should be shown as buttons 0646 // and create the buttons 0647 QUrl placeUrl; 0648 if ((m_placesSelector != nullptr) && !m_showFullPath) { 0649 placeUrl = m_placesSelector->selectedPlaceUrl(); 0650 } 0651 0652 if (!placeUrl.isValid()) { 0653 placeUrl = retrievePlaceUrl(); 0654 } 0655 QString placePath = Utils::trailingSlashRemoved(placeUrl.path()); 0656 0657 const int startIndex = placePath.count(QLatin1Char('/')); 0658 updateButtons(startIndex); 0659 } 0660 } 0661 0662 void KUrlNavigatorPrivate::updateButtons(int startIndex) 0663 { 0664 QUrl currentUrl = q->locationUrl(); 0665 if (!currentUrl.isValid()) { // QFileDialog::setDirectory not called yet 0666 return; 0667 } 0668 0669 const QString path = currentUrl.path(); 0670 0671 const int oldButtonCount = m_navButtons.count(); 0672 0673 int idx = startIndex; 0674 bool hasNext = true; 0675 do { 0676 const bool createButton = (idx - startIndex) >= oldButtonCount; 0677 const bool isFirstButton = (idx == startIndex); 0678 const QString dirName = path.section(QLatin1Char('/'), idx, idx); 0679 hasNext = isFirstButton || !dirName.isEmpty(); 0680 if (hasNext) { 0681 KUrlNavigatorButton *button = nullptr; 0682 if (createButton) { 0683 button = new KUrlNavigatorButton(buttonUrl(idx), q); 0684 button->installEventFilter(q); 0685 button->setForegroundRole(QPalette::WindowText); 0686 q->connect(button, &KUrlNavigatorButton::urlsDroppedOnNavButton, q, [this, button](const QUrl &destination, QDropEvent *event) { 0687 dropUrls(destination, event, button); 0688 }); 0689 0690 auto activatedFunc = [this](const QUrl &url, Qt::MouseButton btn, Qt::KeyboardModifiers modifiers) { 0691 slotNavigatorButtonClicked(url, btn, modifiers); 0692 }; 0693 q->connect(button, &KUrlNavigatorButton::navigatorButtonActivated, q, activatedFunc); 0694 0695 q->connect(button, &KUrlNavigatorButton::finishedTextResolving, q, [this]() { 0696 updateButtonVisibility(); 0697 }); 0698 0699 appendWidget(button); 0700 } else { 0701 button = m_navButtons[idx - startIndex]; 0702 button->setUrl(buttonUrl(idx)); 0703 } 0704 0705 if (isFirstButton) { 0706 button->setText(firstButtonText()); 0707 } 0708 button->setActive(q->isActive()); 0709 0710 if (createButton) { 0711 if (!isFirstButton) { 0712 q->setTabOrder(m_navButtons.constLast(), button); 0713 } 0714 m_navButtons.append(button); 0715 } 0716 0717 ++idx; 0718 button->setActiveSubDirectory(path.section(QLatin1Char('/'), idx, idx)); 0719 } 0720 } while (hasNext); 0721 0722 // delete buttons which are not used anymore 0723 const int newButtonCount = idx - startIndex; 0724 if (newButtonCount < oldButtonCount) { 0725 const auto itBegin = m_navButtons.begin() + newButtonCount; 0726 const auto itEnd = m_navButtons.end(); 0727 for (auto it = itBegin; it != itEnd; ++it) { 0728 auto *navBtn = *it; 0729 navBtn->hide(); 0730 navBtn->deleteLater(); 0731 } 0732 m_navButtons.erase(itBegin, itEnd); 0733 } 0734 0735 q->setTabOrder(m_dropDownButton, m_navButtons.constFirst()); 0736 q->setTabOrder(m_navButtons.constLast(), m_toggleEditableMode); 0737 0738 updateButtonVisibility(); 0739 } 0740 0741 void KUrlNavigatorPrivate::updateButtonVisibility() 0742 { 0743 if (m_editable) { 0744 return; 0745 } 0746 0747 const int buttonsCount = m_navButtons.count(); 0748 if (buttonsCount == 0) { 0749 m_dropDownButton->hide(); 0750 return; 0751 } 0752 0753 // Subtract all widgets from the available width, that must be shown anyway 0754 int availableWidth = q->width() - m_toggleEditableMode->minimumWidth(); 0755 0756 if ((m_placesSelector != nullptr) && m_placesSelector->isVisible()) { 0757 availableWidth -= m_placesSelector->width(); 0758 } 0759 0760 if ((m_protocols != nullptr) && m_protocols->isVisible()) { 0761 availableWidth -= m_protocols->width(); 0762 } 0763 0764 // Check whether buttons must be hidden at all... 0765 int requiredButtonWidth = 0; 0766 for (const auto *button : std::as_const(m_navButtons)) { 0767 requiredButtonWidth += button->minimumWidth(); 0768 } 0769 0770 if (requiredButtonWidth > availableWidth) { 0771 // At least one button must be hidden. This implies that the 0772 // drop-down button must get visible, which again decreases the 0773 // available width. 0774 availableWidth -= m_dropDownButton->width(); 0775 } 0776 0777 // Hide buttons... 0778 bool isLastButton = true; 0779 bool hasHiddenButtons = false; 0780 QList<KUrlNavigatorButton *> buttonsToShow; 0781 for (auto it = m_navButtons.crbegin(); it != m_navButtons.crend(); ++it) { 0782 KUrlNavigatorButton *button = *it; 0783 availableWidth -= button->minimumWidth(); 0784 if ((availableWidth <= 0) && !isLastButton) { 0785 button->hide(); 0786 hasHiddenButtons = true; 0787 } else { 0788 // Don't show the button immediately, as setActive() 0789 // might change the size and a relayout gets triggered 0790 // after showing the button. So the showing of all buttons 0791 // is postponed until all buttons have the correct 0792 // activation state. 0793 buttonsToShow.append(button); 0794 } 0795 isLastButton = false; 0796 } 0797 0798 // All buttons have the correct activation state and 0799 // can be shown now 0800 for (KUrlNavigatorButton *button : std::as_const(buttonsToShow)) { 0801 button->show(); 0802 } 0803 0804 if (hasHiddenButtons) { 0805 m_dropDownButton->show(); 0806 } else { 0807 // Check whether going upwards is possible. If this is the case, show the drop-down button. 0808 QUrl url(m_navButtons.front()->url()); 0809 const bool visible = !url.matches(KIO::upUrl(url), QUrl::StripTrailingSlash) // 0810 && url.scheme() != QLatin1String("baloosearch") // 0811 && url.scheme() != QLatin1String("filenamesearch"); 0812 m_dropDownButton->setVisible(visible); 0813 } 0814 } 0815 0816 QString KUrlNavigatorPrivate::firstButtonText() const 0817 { 0818 QString text; 0819 0820 // The first URL navigator button should get the name of the 0821 // place instead of the directory name 0822 if ((m_placesSelector != nullptr) && !m_showFullPath) { 0823 text = m_placesSelector->selectedPlaceText(); 0824 } 0825 0826 const QUrl currentUrl = q->locationUrl(); 0827 0828 if (text.isEmpty()) { 0829 if (currentUrl.isLocalFile()) { 0830 #ifdef Q_OS_WIN 0831 text = currentUrl.path().length() > 1 ? currentUrl.path().left(2) : QDir::rootPath(); 0832 #else 0833 text = QStringLiteral("/"); 0834 #endif 0835 } 0836 } 0837 0838 if (text.isEmpty()) { 0839 if (currentUrl.path().isEmpty() || currentUrl.path() == QLatin1Char('/')) { 0840 QUrlQuery query(currentUrl); 0841 text = query.queryItemValue(QStringLiteral("title")); 0842 } 0843 } 0844 0845 if (text.isEmpty()) { 0846 text = currentUrl.scheme() + QLatin1Char(':'); 0847 if (!currentUrl.host().isEmpty()) { 0848 text += QLatin1Char(' ') + currentUrl.host(); 0849 } 0850 } 0851 0852 return text; 0853 } 0854 0855 QUrl KUrlNavigatorPrivate::buttonUrl(int index) const 0856 { 0857 if (index < 0) { 0858 index = 0; 0859 } 0860 0861 // Keep scheme, hostname etc. as this is needed for e. g. browsing 0862 // FTP directories 0863 QUrl url = q->locationUrl(); 0864 QString path = url.path(); 0865 0866 if (!path.isEmpty()) { 0867 if (index == 0) { 0868 // prevent the last "/" from being stripped 0869 // or we end up with an empty path 0870 #ifdef Q_OS_WIN 0871 path = path.length() > 1 ? path.left(2) : QDir::rootPath(); 0872 #else 0873 path = QStringLiteral("/"); 0874 #endif 0875 } else { 0876 path = path.section(QLatin1Char('/'), 0, index); 0877 } 0878 } 0879 0880 url.setPath(path); 0881 return url; 0882 } 0883 0884 void KUrlNavigatorPrivate::switchToBreadcrumbMode() 0885 { 0886 q->setUrlEditable(false); 0887 } 0888 0889 void KUrlNavigatorPrivate::deleteButtons() 0890 { 0891 for (KUrlNavigatorButton *button : std::as_const(m_navButtons)) { 0892 button->hide(); 0893 button->deleteLater(); 0894 } 0895 m_navButtons.clear(); 0896 } 0897 0898 QUrl KUrlNavigatorPrivate::retrievePlaceUrl() const 0899 { 0900 QUrl currentUrl = q->locationUrl(); 0901 currentUrl.setPath(QString()); 0902 return currentUrl; 0903 } 0904 0905 // ------------------------------------------------------------------------------------------------ 0906 0907 KUrlNavigator::KUrlNavigator(QWidget *parent) 0908 : KUrlNavigator(nullptr, QUrl{}, parent) 0909 { 0910 } 0911 0912 KUrlNavigator::KUrlNavigator(KFilePlacesModel *placesModel, const QUrl &url, QWidget *parent) 0913 : QWidget(parent) 0914 , d(new KUrlNavigatorPrivate(url, this, placesModel)) 0915 { 0916 const int minHeight = d->m_pathBox->sizeHint().height(); 0917 setMinimumHeight(minHeight); 0918 0919 setMinimumWidth(100); 0920 0921 d->updateContent(); 0922 } 0923 0924 KUrlNavigator::~KUrlNavigator() 0925 { 0926 d->m_dropDownButton->removeEventFilter(this); 0927 d->m_pathBox->removeEventFilter(this); 0928 for (auto *button : std::as_const(d->m_navButtons)) { 0929 button->removeEventFilter(this); 0930 } 0931 } 0932 0933 QUrl KUrlNavigator::locationUrl(int historyIndex) const 0934 { 0935 return d->m_coreUrlNavigator->locationUrl(historyIndex); 0936 } 0937 0938 void KUrlNavigator::saveLocationState(const QByteArray &state) 0939 { 0940 auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>(); 0941 current.state = state; 0942 d->m_coreUrlNavigator->saveLocationState(QVariant::fromValue(current)); 0943 } 0944 0945 QByteArray KUrlNavigator::locationState(int historyIndex) const 0946 { 0947 return d->m_coreUrlNavigator->locationState(historyIndex).value<KUrlNavigatorData>().state; 0948 } 0949 0950 bool KUrlNavigator::goBack() 0951 { 0952 return d->m_coreUrlNavigator->goBack(); 0953 } 0954 0955 bool KUrlNavigator::goForward() 0956 { 0957 return d->m_coreUrlNavigator->goForward(); 0958 } 0959 0960 bool KUrlNavigator::goUp() 0961 { 0962 return d->m_coreUrlNavigator->goUp(); 0963 } 0964 0965 void KUrlNavigator::goHome() 0966 { 0967 if (d->m_homeUrl.isEmpty() || !d->m_homeUrl.isValid()) { 0968 setLocationUrl(QUrl::fromLocalFile(QDir::homePath())); 0969 } else { 0970 setLocationUrl(d->m_homeUrl); 0971 } 0972 } 0973 0974 void KUrlNavigator::setHomeUrl(const QUrl &url) 0975 { 0976 d->m_homeUrl = url; 0977 } 0978 0979 QUrl KUrlNavigator::homeUrl() const 0980 { 0981 return d->m_homeUrl; 0982 } 0983 0984 void KUrlNavigator::setUrlEditable(bool editable) 0985 { 0986 if (d->m_editable != editable) { 0987 d->switchView(); 0988 } 0989 } 0990 0991 bool KUrlNavigator::isUrlEditable() const 0992 { 0993 return d->m_editable; 0994 } 0995 0996 void KUrlNavigator::setShowFullPath(bool show) 0997 { 0998 if (d->m_showFullPath != show) { 0999 d->m_showFullPath = show; 1000 d->updateContent(); 1001 } 1002 } 1003 1004 bool KUrlNavigator::showFullPath() const 1005 { 1006 return d->m_showFullPath; 1007 } 1008 1009 void KUrlNavigator::setActive(bool active) 1010 { 1011 if (active != d->m_active) { 1012 d->m_active = active; 1013 1014 d->m_dropDownButton->setActive(active); 1015 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) { 1016 button->setActive(active); 1017 } 1018 1019 update(); 1020 if (active) { 1021 Q_EMIT activated(); 1022 } 1023 } 1024 } 1025 1026 bool KUrlNavigator::isActive() const 1027 { 1028 return d->m_active; 1029 } 1030 1031 void KUrlNavigator::setPlacesSelectorVisible(bool visible) 1032 { 1033 if (visible == d->m_showPlacesSelector) { 1034 return; 1035 } 1036 1037 if (visible && (d->m_placesSelector == nullptr)) { 1038 // the places selector cannot get visible as no 1039 // places model is available 1040 return; 1041 } 1042 1043 d->m_showPlacesSelector = visible; 1044 d->m_placesSelector->setVisible(visible); 1045 } 1046 1047 bool KUrlNavigator::isPlacesSelectorVisible() const 1048 { 1049 return d->m_showPlacesSelector; 1050 } 1051 1052 QUrl KUrlNavigator::uncommittedUrl() const 1053 { 1054 KUriFilterData filteredData(d->m_pathBox->currentText().trimmed()); 1055 filteredData.setCheckForExecutables(false); 1056 if (KUriFilter::self()->filterUri(filteredData, QStringList{QStringLiteral("kshorturifilter")})) { 1057 return filteredData.uri(); 1058 } else { 1059 return QUrl::fromUserInput(filteredData.typedString()); 1060 } 1061 } 1062 1063 void KUrlNavigator::setLocationUrl(const QUrl &newUrl) 1064 { 1065 d->m_coreUrlNavigator->setCurrentLocationUrl(newUrl); 1066 1067 d->updateContent(); 1068 1069 requestActivation(); 1070 } 1071 1072 void KUrlNavigator::requestActivation() 1073 { 1074 setActive(true); 1075 } 1076 1077 void KUrlNavigator::setFocus() 1078 { 1079 if (isUrlEditable()) { 1080 d->m_pathBox->setFocus(); 1081 } else { 1082 QWidget::setFocus(); 1083 } 1084 } 1085 1086 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1087 void KUrlNavigator::setUrl(const QUrl &url) 1088 { 1089 // deprecated 1090 setLocationUrl(url); 1091 } 1092 #endif 1093 1094 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1095 void KUrlNavigator::saveRootUrl(const QUrl &url) 1096 { 1097 auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>(); 1098 current.rootUrl = url; 1099 d->m_coreUrlNavigator->saveLocationState(QVariant::fromValue(current)); 1100 } 1101 #endif 1102 1103 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1104 void KUrlNavigator::savePosition(int x, int y) 1105 { 1106 auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>(); 1107 current.pos = QPoint(x, y); 1108 d->m_coreUrlNavigator->saveLocationState(QVariant::fromValue(current)); 1109 } 1110 #endif 1111 1112 void KUrlNavigator::keyPressEvent(QKeyEvent *event) 1113 { 1114 if (isUrlEditable() && (event->key() == Qt::Key_Escape)) { 1115 setUrlEditable(false); 1116 } else { 1117 QWidget::keyPressEvent(event); 1118 } 1119 } 1120 1121 void KUrlNavigator::keyReleaseEvent(QKeyEvent *event) 1122 { 1123 QWidget::keyReleaseEvent(event); 1124 } 1125 1126 void KUrlNavigator::mousePressEvent(QMouseEvent *event) 1127 { 1128 if (event->button() == Qt::MiddleButton) { 1129 requestActivation(); 1130 } 1131 QWidget::mousePressEvent(event); 1132 } 1133 1134 void KUrlNavigator::mouseReleaseEvent(QMouseEvent *event) 1135 { 1136 if (event->button() == Qt::MiddleButton) { 1137 const QRect bounds = d->m_toggleEditableMode->geometry(); 1138 if (bounds.contains(event->pos())) { 1139 // The middle mouse button has been clicked above the 1140 // toggle-editable-mode-button. Paste the clipboard content 1141 // as location URL. 1142 QClipboard *clipboard = QApplication::clipboard(); 1143 const QMimeData *mimeData = clipboard->mimeData(); 1144 if (mimeData->hasText()) { 1145 const QString text = mimeData->text(); 1146 setLocationUrl(QUrl::fromUserInput(text)); 1147 } 1148 } 1149 } 1150 QWidget::mouseReleaseEvent(event); 1151 } 1152 1153 void KUrlNavigator::resizeEvent(QResizeEvent *event) 1154 { 1155 QTimer::singleShot(0, this, [this]() { 1156 d->updateButtonVisibility(); 1157 }); 1158 QWidget::resizeEvent(event); 1159 } 1160 1161 void KUrlNavigator::wheelEvent(QWheelEvent *event) 1162 { 1163 setActive(true); 1164 QWidget::wheelEvent(event); 1165 } 1166 1167 bool KUrlNavigator::eventFilter(QObject *watched, QEvent *event) 1168 { 1169 switch (event->type()) { 1170 case QEvent::FocusIn: 1171 if (watched == d->m_pathBox) { 1172 requestActivation(); 1173 setFocus(); 1174 } 1175 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) { 1176 button->setShowMnemonic(true); 1177 } 1178 break; 1179 1180 case QEvent::FocusOut: 1181 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) { 1182 button->setShowMnemonic(false); 1183 } 1184 break; 1185 1186 default: 1187 break; 1188 } 1189 1190 return QWidget::eventFilter(watched, event); 1191 } 1192 1193 int KUrlNavigator::historySize() const 1194 { 1195 return d->m_coreUrlNavigator->historySize(); 1196 } 1197 1198 int KUrlNavigator::historyIndex() const 1199 { 1200 return d->m_coreUrlNavigator->historyIndex(); 1201 } 1202 1203 KUrlComboBox *KUrlNavigator::editor() const 1204 { 1205 return d->m_pathBox; 1206 } 1207 1208 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 103) 1209 void KUrlNavigator::setCustomProtocols(const QStringList &protocols) 1210 { 1211 setSupportedSchemes(protocols); 1212 } 1213 #endif 1214 1215 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(5, 103) 1216 QStringList KUrlNavigator::customProtocols() const 1217 { 1218 return supportedSchemes(); 1219 } 1220 #endif 1221 1222 void KUrlNavigator::setSupportedSchemes(const QStringList &schemes) 1223 { 1224 d->m_customProtocols = schemes; 1225 d->m_protocols->setCustomProtocols(d->m_customProtocols); 1226 } 1227 1228 QStringList KUrlNavigator::supportedSchemes() const 1229 { 1230 return d->m_customProtocols; 1231 } 1232 1233 QWidget *KUrlNavigator::dropWidget() const 1234 { 1235 return d->m_dropWidget; 1236 } 1237 1238 void KUrlNavigator::setShowHiddenFolders(bool showHiddenFolders) 1239 { 1240 d->m_subfolderOptions.showHidden = showHiddenFolders; 1241 } 1242 1243 bool KUrlNavigator::showHiddenFolders() const 1244 { 1245 return d->m_subfolderOptions.showHidden; 1246 } 1247 1248 void KUrlNavigator::setSortHiddenFoldersLast(bool sortHiddenFoldersLast) 1249 { 1250 d->m_subfolderOptions.sortHiddenLast = sortHiddenFoldersLast; 1251 } 1252 1253 bool KUrlNavigator::sortHiddenFoldersLast() const 1254 { 1255 return d->m_subfolderOptions.sortHiddenLast; 1256 } 1257 1258 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1259 const QUrl &KUrlNavigator::url() const 1260 { 1261 // deprecated 1262 1263 // Workaround required because of flawed interface ('const QUrl&' is returned 1264 // instead of 'QUrl'): remember the URL to prevent a dangling pointer 1265 static QUrl url; 1266 url = locationUrl(); 1267 return url; 1268 } 1269 #endif 1270 1271 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1272 QUrl KUrlNavigator::url(int index) const 1273 { 1274 // deprecated 1275 return d->buttonUrl(index); 1276 } 1277 #endif 1278 1279 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1280 QUrl KUrlNavigator::historyUrl(int historyIndex) const 1281 { 1282 // deprecated 1283 return locationUrl(historyIndex); 1284 } 1285 #endif 1286 1287 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1288 const QUrl &KUrlNavigator::savedRootUrl() const 1289 { 1290 // deprecated 1291 // Workaround required because of flawed interface ('const QUrl&' is returned 1292 // instead of 'QUrl'): remember the root URL to prevent a dangling pointer 1293 static QUrl rootUrl; 1294 const auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>(); 1295 rootUrl = current.rootUrl; 1296 return rootUrl; 1297 } 1298 #endif 1299 1300 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1301 QPoint KUrlNavigator::savedPosition() const 1302 { 1303 // deprecated 1304 const auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>(); 1305 return current.pos; 1306 } 1307 #endif 1308 1309 #if KIOFILEWIDGETS_BUILD_DEPRECATED_SINCE(4, 5) 1310 void KUrlNavigator::setHomeUrl(const QString &homeUrl) 1311 { 1312 // deprecated 1313 setLocationUrl(QUrl::fromUserInput(homeUrl)); 1314 } 1315 #endif 1316 1317 #include "moc_kurlnavigator.cpp"