10#include "kurlnavigator.h"
11#include "kcoreurlnavigator.h"
13#include "../utils_p.h"
14#include "kurlnavigatorbutton_p.h"
15#include "kurlnavigatordropdownbutton_p.h"
16#include "kurlnavigatorpathselectoreventfilter_p.h"
17#include "kurlnavigatorplacesselector_p.h"
18#include "kurlnavigatorschemecombo_p.h"
19#include "kurlnavigatortogglebutton_p.h"
22#include <KLocalizedString>
24#include <kfileplacesmodel.h>
25#include <kprotocolinfo.h>
26#include <kurifilter.h>
27#include <kurlcombobox.h>
28#include <kurlcompletion.h>
30#include <QActionGroup>
31#include <QApplication>
40#include <QMimeDatabase>
47using namespace KDEPrivate;
49struct KUrlNavigatorData {
52Q_DECLARE_METATYPE(KUrlNavigatorData)
54class KUrlNavigatorPrivate
59 ~KUrlNavigatorPrivate()
61 m_dropDownButton->removeEventFilter(q);
63 m_toggleEditableMode->removeEventFilter(q);
65 for (KUrlNavigatorButton *button :
std::as_const(m_navButtons)) {
66 button->removeEventFilter(q);
71 void applyUncommittedUrl();
72 void slotApplyUrl(
QUrl url);
75 bool slotCheckFilters(
const QString &text);
77 void slotReturnPressed();
78 void slotSchemeChanged(
const QString &);
79 void openPathSelectorMenu();
86 void appendWidget(
QWidget *widget,
int stretch = 0);
92 void slotToggleEditableButtonPressed();
101 void dropUrls(
const QUrl &destination,
QDropEvent *event, KUrlNavigatorButton *dropButton);
114 void openContextMenu(
const QPoint &p);
116 void slotPathBoxChanged(
const QString &text);
118 void updateContent();
128 void updateButtons(
int startIndex);
135 void updateButtonVisibility();
140 QString firstButtonText()
const;
145 QUrl buttonUrl(
int index)
const;
147 void switchToBreadcrumbMode();
153 void deleteButtons();
162 QUrl retrievePlaceUrl()
const;
171 KUrlNavigatorPlacesSelector *m_placesSelector =
nullptr;
173 KUrlNavigatorSchemeCombo *m_schemes =
nullptr;
174 KUrlNavigatorDropDownButton *m_dropDownButton =
nullptr;
175 KUrlNavigatorButtonBase *m_toggleEditableMode =
nullptr;
176 QWidget *m_dropWidget =
nullptr;
178 bool m_editable =
false;
179 bool m_active =
true;
180 bool m_showPlacesSelector =
false;
181 bool m_showFullPath =
false;
184 bool showHidden =
false;
185 bool sortHiddenLast =
false;
186 } m_subfolderOptions;
192 , m_showPlacesSelector(placesModel != nullptr)
194 m_layout->setSpacing(0);
195 m_layout->setContentsMargins(0, 0, 0, 0);
197 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::currentLocationUrlChanged, q, [
this]() {
198 Q_EMIT q->urlChanged(m_coreUrlNavigator->currentLocationUrl());
201 Q_EMIT q->urlAboutToBeChanged(url);
203 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historySizeChanged, q, [
this]() {
204 Q_EMIT q->historyChanged();
206 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historyIndexChanged, q, [
this]() {
207 Q_EMIT q->historyChanged();
210 Q_EMIT q->historyChanged();
213 Q_EMIT q->urlSelectionRequested(url);
217 q->setAutoFillBackground(
false);
219 if (placesModel !=
nullptr) {
220 m_placesSelector =
new KUrlNavigatorPlacesSelector(q, placesModel);
224 auto updateContentFunc = [
this]() {
233 m_schemes =
new KUrlNavigatorSchemeCombo(
QString(), q);
234 q->connect(m_schemes, &KUrlNavigatorSchemeCombo::activated, q, [
this](
const QString &schene) {
235 slotSchemeChanged(schene);
239 m_dropDownButton =
new KUrlNavigatorDropDownButton(q);
241 m_dropDownButton->installEventFilter(q);
242 q->connect(m_dropDownButton, &KUrlNavigatorDropDownButton::clicked, q, [
this]() {
243 openPathSelectorMenu();
247 m_pathBox =
new KUrlComboBox(KUrlComboBox::Directories,
true, q);
249 m_pathBox->installEventFilter(q);
252 m_pathBox->setCompletionObject(kurlCompletion);
253 m_pathBox->setAutoDeleteCompletionObject(
true);
261 slotPathBoxChanged(text);
266 m_toggleEditableMode =
new KUrlNavigatorToggleButton(q);
267 m_toggleEditableMode->installEventFilter(q);
268 m_toggleEditableMode->setMinimumWidth(20);
269 q->connect(m_toggleEditableMode, &KUrlNavigatorToggleButton::clicked, q, [
this]() {
270 slotToggleEditableButtonPressed();
273 if (m_placesSelector !=
nullptr) {
274 m_layout->addWidget(m_placesSelector);
276 m_layout->addWidget(m_schemes);
277 m_layout->addWidget(m_dropDownButton);
278 m_layout->addWidget(m_pathBox, 1);
279 m_layout->addWidget(m_toggleEditableMode);
287void KUrlNavigatorPrivate::appendWidget(
QWidget *widget,
int stretch)
292void KUrlNavigatorPrivate::slotApplyUrl(
QUrl url)
302 url.
setPath(QStringLiteral(
"/"));
309 m_pathBox->
setUrls(urls, KUrlComboBox::RemoveBottom);
317bool KUrlNavigatorPrivate::slotCheckFilters(
const QString &text)
320 filteredData.setCheckForExecutables(
false);
322 const auto filtersList =
QStringList{QStringLiteral(
"kshorturifilter")};
325 slotApplyUrl(filteredData.uri());
330void KUrlNavigatorPrivate::applyUncommittedUrl()
340 if (slotCheckFilters(text)) {
360 if (!job->error() && job->statResult().isDir()) {
361 slotApplyUrl(job->url());
366 if (slotCheckFilters(text)) {
375void KUrlNavigatorPrivate::slotReturnPressed()
377 applyUncommittedUrl();
385 auto switchModeFunc = [
this]() {
386 switchToBreadcrumbMode();
392void KUrlNavigatorPrivate::slotSchemeChanged(
const QString &scheme)
394 Q_ASSERT(m_editable);
402 url.
setPath(QStringLiteral(
"/"));
412void KUrlNavigatorPrivate::openPathSelectorMenu()
414 if (m_navButtons.
count() <= 0) {
423 auto *popupFilter =
new KUrlNavigatorPathSelectorEventFilter(popup.
data());
425 popup->installEventFilter(popupFilter);
427 const QUrl placeUrl = retrievePlaceUrl();
435 dirName = QStringLiteral(
"/");
441 const QString text = spacer + dirName;
444 const QUrl currentUrl = buttonUrl(idx);
445 if (currentUrl == firstVisibleUrl) {
446 popup->addSeparator();
449 popup->addAction(action);
454 }
while (!dirName.isEmpty());
457 const QAction *activatedAction = popup->exec(pos);
458 if (activatedAction !=
nullptr) {
465 popup->deleteLater();
469void KUrlNavigatorPrivate::slotToggleEditableButtonPressed()
472 applyUncommittedUrl();
478void KUrlNavigatorPrivate::switchView()
480 m_toggleEditableMode->setFocus();
481 m_editable = !m_editable;
482 m_toggleEditableMode->setChecked(m_editable);
492void KUrlNavigatorPrivate::dropUrls(
const QUrl &destination,
QDropEvent *event, KUrlNavigatorButton *dropButton)
494 if (
event->mimeData()->hasUrls()) {
495 m_dropWidget = qobject_cast<QWidget *>(dropButton);
513void KUrlNavigatorPrivate::openContextMenu(
const QPoint &p)
529 popup->addSeparator();
535 if (isTabSignal || isWindowSignal) {
536 auto it = std::find_if(m_navButtons.
cbegin(), m_navButtons.
cend(), [&p](
const KUrlNavigatorButton *button) {
537 return button->geometry().contains(p);
539 if (it != m_navButtons.
cend()) {
540 const auto *button = *it;
541 const QUrl url = button->
url();
542 const QString text = button->text();
545 QAction *openInTab = popup->addAction(
QIcon::fromTheme(QStringLiteral(
"tab-new")),
i18nc(
"@item:inmenu",
"Open \"%1\" in New Tab", text));
551 if (isWindowSignal) {
553 popup->addAction(
QIcon::fromTheme(QStringLiteral(
"window-new")),
i18nc(
"@item:inmenu",
"Open \"%1\" in New Window", text));
562 QAction *editAction = popup->addAction(
i18n(
"Edit"));
565 QAction *navigateAction = popup->addAction(
i18n(
"Navigate"));
577 popup->addSeparator();
580 QAction *showFullPathAction = popup->addAction(
i18n(
"Show Full Path"));
585 if (activatedAction == copyAction) {
589 }
else if (activatedAction == pasteAction) {
591 }
else if (activatedAction == editAction) {
593 }
else if (activatedAction == navigateAction) {
595 }
else if (activatedAction == showFullPathAction) {
601 popup->deleteLater();
605void KUrlNavigatorPrivate::slotPathBoxChanged(
const QString &text)
609 m_schemes->setScheme(scheme);
610 if (m_supportedSchemes.
count() != 1) {
618void KUrlNavigatorPrivate::updateContent()
621 if (m_placesSelector !=
nullptr) {
622 m_placesSelector->updateSelection(currentUrl);
627 m_dropDownButton->hide();
634 m_pathBox->
setUrl(currentUrl);
646 if ((m_placesSelector !=
nullptr) && !m_showFullPath) {
647 placeUrl = m_placesSelector->selectedPlaceUrl();
651 placeUrl = retrievePlaceUrl();
653 QString placePath = Utils::trailingSlashRemoved(placeUrl.
path());
656 updateButtons(startIndex);
660void KUrlNavigatorPrivate::updateButtons(
int startIndex)
669 const int oldButtonCount = m_navButtons.
count();
671 int idx = startIndex;
674 const bool createButton = (idx - startIndex) >= oldButtonCount;
675 const bool isFirstButton = (idx == startIndex);
677 hasNext = isFirstButton || !dirName.
isEmpty();
679 KUrlNavigatorButton *button =
nullptr;
681 button =
new KUrlNavigatorButton(buttonUrl(idx), q);
682 button->installEventFilter(q);
684 q->
connect(button, &KUrlNavigatorButton::urlsDroppedOnNavButton, q, [
this, button](
const QUrl &destination,
QDropEvent *event) {
685 dropUrls(destination, event, button);
689 slotNavigatorButtonClicked(url, btn, modifiers);
691 q->
connect(button, &KUrlNavigatorButton::navigatorButtonActivated, q, activatedFunc);
693 q->
connect(button, &KUrlNavigatorButton::finishedTextResolving, q, [
this]() {
694 updateButtonVisibility();
697 appendWidget(button);
699 button = m_navButtons[idx - startIndex];
700 button->setUrl(buttonUrl(idx));
704 button->setText(firstButtonText());
709 if (!isFirstButton) {
712 m_navButtons.
append(button);
721 const int newButtonCount = idx - startIndex;
722 if (newButtonCount < oldButtonCount) {
723 const auto itBegin = m_navButtons.
begin() + newButtonCount;
724 const auto itEnd = m_navButtons.
end();
725 for (
auto it = itBegin; it != itEnd; ++it) {
728 navBtn->deleteLater();
730 m_navButtons.
erase(itBegin, itEnd);
736 updateButtonVisibility();
739void KUrlNavigatorPrivate::updateButtonVisibility()
745 const int buttonsCount = m_navButtons.
count();
746 if (buttonsCount == 0) {
747 m_dropDownButton->hide();
752 int availableWidth = q->
width() - m_toggleEditableMode->minimumWidth();
754 if ((m_placesSelector !=
nullptr) && m_placesSelector->isVisible()) {
755 availableWidth -= m_placesSelector->width();
758 if ((m_schemes !=
nullptr) && m_schemes->isVisible()) {
759 availableWidth -= m_schemes->width();
763 int requiredButtonWidth = 0;
764 for (
const auto *button :
std::as_const(m_navButtons)) {
765 requiredButtonWidth += button->minimumWidth();
768 if (requiredButtonWidth > availableWidth) {
772 availableWidth -= m_dropDownButton->width();
776 bool isLastButton =
true;
777 bool hasHiddenButtons =
false;
779 for (
auto it = m_navButtons.
crbegin(); it != m_navButtons.
crend(); ++it) {
780 KUrlNavigatorButton *button = *it;
781 availableWidth -= button->minimumWidth();
782 if ((availableWidth <= 0) && !isLastButton) {
784 hasHiddenButtons =
true;
791 buttonsToShow.
append(button);
793 isLastButton =
false;
798 for (KUrlNavigatorButton *button :
std::as_const(buttonsToShow)) {
802 if (hasHiddenButtons) {
803 m_dropDownButton->show();
810 m_dropDownButton->setVisible(visible);
814QString KUrlNavigatorPrivate::firstButtonText()
const
820 if ((m_placesSelector !=
nullptr) && !m_showFullPath) {
821 text = m_placesSelector->selectedPlaceText();
831 text = QStringLiteral(
"/");
839 text =
query.queryItemValue(QStringLiteral(
"title"));
853QUrl KUrlNavigatorPrivate::buttonUrl(
int index)
const
871 path = QStringLiteral(
"/");
882void KUrlNavigatorPrivate::switchToBreadcrumbMode()
887void KUrlNavigatorPrivate::deleteButtons()
889 for (KUrlNavigatorButton *button :
std::as_const(m_navButtons)) {
891 button->deleteLater();
893 m_navButtons.
clear();
896QUrl KUrlNavigatorPrivate::retrievePlaceUrl()
const
912 , d(new KUrlNavigatorPrivate(url, this, placesModel))
914 const int minHeight = d->m_pathBox->sizeHint().height();
922KUrlNavigator::~KUrlNavigator()
924 d->m_dropDownButton->removeEventFilter(
this);
925 d->m_pathBox->removeEventFilter(
this);
926 for (
auto *button :
std::as_const(d->m_navButtons)) {
927 button->removeEventFilter(
this);
933 return d->m_coreUrlNavigator->locationUrl(
historyIndex);
938 auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>();
939 current.state = state;
945 return d->m_coreUrlNavigator->locationState(
historyIndex).value<KUrlNavigatorData>().state;
950 return d->m_coreUrlNavigator->goBack();
955 return d->m_coreUrlNavigator->goForward();
960 return d->m_coreUrlNavigator->goUp();
965 if (d->m_homeUrl.isEmpty() || !d->m_homeUrl.isValid()) {
977QUrl KUrlNavigator::homeUrl()
const
984 if (d->m_editable != editable) {
991 return d->m_editable;
996 if (d->m_showFullPath !=
show) {
997 d->m_showFullPath =
show;
1004 return d->m_showFullPath;
1009 if (active != d->m_active) {
1010 d->m_active = active;
1012 d->m_dropDownButton->setActive(active);
1013 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) {
1014 button->setActive(active);
1031 if (
visible == d->m_showPlacesSelector) {
1035 if (
visible && (d->m_placesSelector ==
nullptr)) {
1041 d->m_showPlacesSelector =
visible;
1042 d->m_placesSelector->setVisible(
visible);
1047 return d->m_showPlacesSelector;
1052 KUriFilterData filteredData(d->m_pathBox->currentText().trimmed());
1055 return filteredData.
uri();
1063 d->m_coreUrlNavigator->setCurrentLocationUrl(newUrl);
1078 d->m_pathBox->setFocus();
1109 const QRect bounds = d->m_toggleEditableMode->geometry();
1128 d->updateButtonVisibility();
1141 switch (
event->type()) {
1143 if (watched == d->m_pathBox) {
1147 for (KUrlNavigatorButton *button :
std::as_const(d->m_navButtons)) {
1148 button->setShowMnemonic(
true);
1153 for (KUrlNavigatorButton *button :
std::as_const(d->m_navButtons)) {
1154 button->setShowMnemonic(
false);
1167 return d->m_coreUrlNavigator->historySize();
1172 return d->m_coreUrlNavigator->historyIndex();
1177 return d->m_pathBox;
1182 d->m_supportedSchemes = schemes;
1183 d->m_schemes->setSupportedSchemes(d->m_supportedSchemes);
1188 return d->m_supportedSchemes;
1193 return d->m_dropWidget;
1203 return d->m_subfolderOptions.showHidden;
1213 return d->m_subfolderOptions.sortHiddenLast;
1216#include "moc_kurlnavigator.cpp"
void setEditUrl(const QUrl &url)
void returnPressed(const QString &text)
Object that helps with keeping track of URLs in file-manager like interfaces.
Q_SIGNAL void urlSelectionRequested(const QUrl &url)
When the URL is changed and the new URL (e.g. /home/user1/) is a parent of the previous URL (e....
Q_SIGNAL void currentUrlAboutToChange(const QUrl &newUrl)
Is emitted, before the location URL is going to be changed to newUrl.
int historyIndex
The history index of the current location, where 0 <= history index < KCoreUrlNavigator::historySize(...
Q_SIGNAL void historyChanged()
Is emitted, if the history has been changed.
Q_INVOKABLE QUrl locationUrl(int historyIndex=-1) const
This class is a list view model.
static QString protocolClass(const QString &protocol)
Returns the protocol class for the specified protocol.
This class is a basic messaging class used to exchange filtering information between the filter plugi...
QUrl uri() const
Returns the filtered or the original URL.
QString typedString() const
The string as typed by the user, before any URL processing is done.
void setCheckForExecutables(bool check)
Check whether the provided uri is executable or not.
static KUriFilter * self()
Returns an instance of KUriFilter.
bool filterUri(KUriFilterData &data, const QStringList &filters=QStringList())
Filters data using the specified filters.
This combobox shows a number of recent URLs/directories, as well as some default directories.
void setUrls(const QStringList &urls)
Inserts urls into the combobox below the "default urls" (see addDefaultUrl).
void setUrl(const QUrl &url)
Sets the current url.
void urlActivated(const QUrl &url)
Emitted when an item was clicked at.
This class does completion of URLs including user directories (~user) and environment variables.
Widget that allows to navigate through the paths of an URL.
void newWindowRequested(const QUrl &url)
Is emitted if the URL url should be opened in a new window because the user left-clicked on a breadcr...
void setShowFullPath(bool show)
Shows the full path of the URL even if a place represents a part of the URL.
void setSortHiddenFoldersLast(bool sortHiddenFoldersLast)
Sets whether to sort hidden folders in the subdirectories popup last.
void setPlacesSelectorVisible(bool visible)
Sets the places selector visible, if visible is true.
void setLocationUrl(const QUrl &url)
Sets the location to url.
bool goUp()
Goes up one step of the URL path and remembers the old path in the history.
bool showHiddenFolders() const
Returns whether to show hidden folders in the subdirectories popup.
void editableStateChanged(bool editable)
Is emitted, if the editable state for the URL has been changed (see KUrlNavigator::setUrlEditable()).
QUrl uncommittedUrl() const
KUrlComboBox * editor() const
QStringList supportedSchemes() const
Returns the URL schemes that the navigator should allow navigating to.
KUrlNavigator(QWidget *parent=nullptr)
bool sortHiddenFoldersLast() const
Returns whether to sort hidden folders in the subdirectories popup last.
void tabRequested(const QUrl &url)
Is emitted if the URL url should be opened in a new inactive tab because the user clicked on a breadc...
void saveLocationState(const QByteArray &state)
Saves the location state described by state for the current location.
void goHome()
Goes to the home URL and remembers the old URL in the history.
void setHomeUrl(const QUrl &url)
Sets the home URL used by KUrlNavigator::goHome().
void activeTabRequested(const QUrl &url)
Is emitted if the URL url should be opened in a new active tab because the user clicked on a breadcru...
bool goBack()
Goes back one step in the URL history.
QUrl locationUrl(int historyIndex=-1) const
void requestActivation()
Activates the URL navigator (KUrlNavigator::isActive() will return true) and emits the signal KUrlNav...
void setUrlEditable(bool editable)
Allows to edit the URL of the navigation bar if editable is true, and sets the focus accordingly.
bool isPlacesSelectorVisible() const
bool showFullPath() const
bool goForward()
Goes forward one step in the URL history.
void setShowHiddenFolders(bool showHiddenFolders)
Sets whether to show hidden folders in the subdirectories popup.
void urlsDropped(const QUrl &destination, QDropEvent *event)
Is emitted if a dropping has been done above the destination destination.
void setActive(bool active)
Set the URL navigator to the active mode, if active is true.
QWidget * dropWidget() const
The child widget that received the QDropEvent when dropping on the URL navigator.
void activated()
Is emitted, if the URL navigator has been activated by an user interaction.
QByteArray locationState(int historyIndex=-1) const
bool isUrlEditable() const
void returnPressed()
This signal is emitted when the Return or Enter key is pressed.
void setSupportedSchemes(const QStringList &schemes)
Set the URL schemes that the navigator should allow navigating to.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
KIOCORE_EXPORT QUrl upUrl(const QUrl &url)
This function is useful to implement the "Up" button in a file manager for example.
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
@ StatBasic
Filename, access, type, size, linkdest.
@ StatResolveSymlink
Resolve symlinks.
QString path(const QString &relativePath)
const QList< QKeySequence > & openContextMenu()
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
void rowsInserted(const QModelIndex &parent, int first, int last)
void rowsRemoved(const QModelIndex &parent, int first, int last)
QVariant data() const const
void setData(const QVariant &data)
void triggered(bool checked)
QAction * addAction(QAction *action)
virtual int count() const const override
const QMimeData * mimeData(Mode mode) const const
void setMimeData(QMimeData *src, Mode mode)
QString text(Mode mode) const const
AdjustToContentsOnFirstShow
void editTextChanged(const QString &text)
Qt::KeyboardModifiers keyboardModifiers()
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
const_iterator cbegin() const const
const_iterator cend() const const
const T & constFirst() const const
const T & constLast() const const
qsizetype count() const const
const_reverse_iterator crbegin() const const
const_reverse_iterator crend() const const
iterator erase(const_iterator begin, const_iterator end)
void prepend(parameter_type value)
qsizetype removeAll(const AT &t)
bool hasText() const const
void setText(const QString &text)
QString text() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool eventFilter(QObject *watched, QEvent *event)
bool isSignalConnected(const QMetaMethod &signal) const const
void removeEventFilter(QObject *obj)
bool contains(const QPoint &point, bool proper) const const
qsizetype count() const const
QString & append(QChar ch)
bool isEmpty() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
typedef KeyboardModifiers
QUrl fromLocalFile(const QString &localFile)
QString host(ComponentFormattingOptions options) const const
bool isEmpty() const const
bool isLocalFile() const const
bool isValid() const const
bool matches(const QUrl &url, FormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
QString scheme() const const
void setAuthority(const QString &authority, ParsingMode mode)
void setPath(const QString &path, ParsingMode mode)
void setScheme(const QString &scheme)
QString toDisplayString(FormattingOptions options) const const
QString toString(FormattingOptions options) const const
QString url(FormattingOptions options) const const
QVariant fromValue(T &&value)
QString toString() const const