KIO

kurlnavigator.cpp
1/*
2 SPDX-FileCopyrightText: 2006-2010 Peter Penz <peter.penz@gmx.at>
3 SPDX-FileCopyrightText: 2006 Aaron J. Seigo <aseigo@kde.org>
4 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
5 SPDX-FileCopyrightText: 2007 Urs Wolfer <uwolfer @ kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kurlnavigator.h"
11#include "kcoreurlnavigator.h"
12
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"
20
21#include <KIO/StatJob>
22#include <KLocalizedString>
23#include <kfileitem.h>
24#include <kfileplacesmodel.h>
25#include <kprotocolinfo.h>
26#include <kurifilter.h>
27#include <kurlcombobox.h>
28#include <kurlcompletion.h>
29
30#include <QActionGroup>
31#include <QApplication>
32#include <QClipboard>
33#include <QDir>
34#include <QDropEvent>
35#include <QHBoxLayout>
36#include <QKeyEvent>
37#include <QMenu>
38#include <QMetaMethod>
39#include <QMimeData>
40#include <QMimeDatabase>
41#include <QTimer>
42#include <QUrlQuery>
43
44#include <algorithm>
45#include <numeric>
46#include <optional>
47
48using namespace KDEPrivate;
49
50struct KUrlNavigatorData {
51 QByteArray state;
52};
53Q_DECLARE_METATYPE(KUrlNavigatorData)
54
55class KUrlNavigatorPrivate
56{
57public:
58 KUrlNavigatorPrivate(const QUrl &url, KUrlNavigator *qq, KFilePlacesModel *placesModel);
59
60 ~KUrlNavigatorPrivate()
61 {
62 m_dropDownButton->removeEventFilter(q);
63 m_pathBox->removeEventFilter(q);
64 m_toggleEditableMode->removeEventFilter(q);
65
66 for (KUrlNavigatorButton *button : std::as_const(m_navButtons)) {
67 button->removeEventFilter(q);
68 }
69 }
70
71 enum class ApplyUrlMethod {
72 Apply,
73 Tab,
74 ActiveTab,
75 NewWindow
76 };
77
78 /** Applies the edited URL in m_pathBox to the URL navigator */
79 void applyUncommittedUrl(ApplyUrlMethod method);
80 void slotApplyUrl(QUrl url);
81
82 // Returns the URI if "text" matched a URI filter (i.e. was fitlered),
83 // otherwise returns nullopt.
84 std::optional<QUrl> checkFilters(const QString &text);
85
86 void slotReturnPressed();
87 void slotSchemeChanged(const QString &);
88 void openPathSelectorMenu();
89
90 /**
91 * Appends the widget at the end of the URL navigator. It is assured
92 * that the filler widget remains as last widget to fill the remaining
93 * width.
94 */
95 void appendWidget(QWidget *widget, int stretch = 0);
96
97 /**
98 * This slot is connected to the clicked signal of the navigation bar button. It calls switchView().
99 * Moreover, if switching from "editable" mode to the breadcrumb view, it calls applyUncommittedUrl().
100 */
101 void slotToggleEditableButtonPressed();
102
103 /**
104 * Switches the navigation bar between the breadcrumb view and the
105 * traditional view (see setUrlEditable()).
106 */
107 void switchView();
108
109 /** Emits the signal urlsDropped(). */
110 void dropUrls(const QUrl &destination, QDropEvent *event, KUrlNavigatorButton *dropButton);
111
112 /**
113 * Is invoked when a navigator button has been clicked.
114 * Different combinations of mouse clicks and keyboard modifiers have different effects on how
115 * the url is opened. The behaviours are the following:
116 * - shift+middle-click or ctrl+shift+left-click => activeTabRequested() signal is emitted
117 * - ctrl+left-click or middle-click => tabRequested() signal is emitted
118 * - shift+left-click => newWindowRequested() signal is emitted
119 * - left-click => open the new url in-place
120 */
121 void slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers);
122
123 void openContextMenu(const QPoint &p);
124
125 void slotPathBoxChanged(const QString &text);
126
127 void updateContent();
128
129 /**
130 * Updates all buttons to have one button for each part of the
131 * current URL. Existing buttons, which are available by m_navButtons,
132 * are reused if possible. If the URL is longer, new buttons will be
133 * created, if the URL is shorter, the remaining buttons will be deleted.
134 * @param startIndex Start index of URL part (/), where the buttons
135 * should be created for each following part.
136 */
137 void updateButtons(int startIndex);
138
139 /**
140 * Updates the visibility state of all buttons describing the URL. If the
141 * width of the URL navigator is too small, the buttons representing the upper
142 * paths of the URL will be hidden and moved to a drop down menu.
143 */
144 void updateButtonVisibility();
145
146 /**
147 * Set a sensible Tab key focus order which goes left to right all the way
148 * through all visible child widgets. For right-to-left layout directions
149 * the order goes right to left.
150 * The first widget is set as the focusProxy() of this KUrlNavigator.
151 */
152 void updateTabOrder();
153
154 /**
155 * @return Text for the first button of the URL navigator.
156 */
157 QString firstButtonText() const;
158
159 /**
160 * Returns the URL that should be applied for the button with the index \a index.
161 */
162 QUrl buttonUrl(int index) const;
163
164 void switchToBreadcrumbMode();
165
166 /**
167 * Deletes all URL navigator buttons. m_navButtons is
168 * empty after this operation.
169 */
170 void deleteButtons();
171
172 /**
173 * Retrieves the place url for the current url.
174 * E. g. for the path "fish://root@192.168.0.2/var/lib" the string
175 * "fish://root@192.168.0.2" will be returned, which leads to the
176 * navigation indication 'Custom Path > var > lib". For e. g.
177 * "settings:///System/" the path "settings://" will be returned.
178 */
179 QUrl retrievePlaceUrl() const;
180
181 KUrlNavigator *const q;
182
183 QHBoxLayout *m_layout = new QHBoxLayout(q);
184 KCoreUrlNavigator *m_coreUrlNavigator = nullptr;
185 QList<KUrlNavigatorButton *> m_navButtons;
186 QStringList m_supportedSchemes;
187 QUrl m_homeUrl;
188 KUrlNavigatorPlacesSelector *m_placesSelector = nullptr;
189 KUrlComboBox *m_pathBox = nullptr;
190 KUrlNavigatorSchemeCombo *m_schemes = nullptr;
191 KUrlNavigatorDropDownButton *m_dropDownButton = nullptr;
192 KUrlNavigatorButtonBase *m_toggleEditableMode = nullptr;
193 QWidget *m_dropWidget = nullptr;
194 QWidget *m_badgeWidgetContainer = nullptr;
195
196 bool m_editable = false;
197 bool m_active = true;
198 bool m_showPlacesSelector = false;
199 bool m_showFullPath = false;
200
201 struct {
202 bool showHidden = false;
203 bool sortHiddenLast = false;
204 } m_subfolderOptions;
205};
206
207KUrlNavigatorPrivate::KUrlNavigatorPrivate(const QUrl &url, KUrlNavigator *qq, KFilePlacesModel *placesModel)
208 : q(qq)
209 , m_coreUrlNavigator(new KCoreUrlNavigator(url, qq))
210 , m_showPlacesSelector(placesModel != nullptr)
211{
212 m_layout->setSpacing(0);
213 m_layout->setContentsMargins(0, 0, 0, 0);
214
215 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::currentLocationUrlChanged, q, [this]() {
216 Q_EMIT q->urlChanged(m_coreUrlNavigator->currentLocationUrl());
217 });
218 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::currentUrlAboutToChange, q, [this](const QUrl &url) {
219 Q_EMIT q->urlAboutToBeChanged(url);
220 });
221 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historySizeChanged, q, [this]() {
222 Q_EMIT q->historyChanged();
223 });
224 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historyIndexChanged, q, [this]() {
225 Q_EMIT q->historyChanged();
226 });
227 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::historyChanged, q, [this]() {
228 Q_EMIT q->historyChanged();
229 });
230 q->connect(m_coreUrlNavigator, &KCoreUrlNavigator::urlSelectionRequested, q, [this](const QUrl &url) {
231 Q_EMIT q->urlSelectionRequested(url);
232 });
233
234 // initialize the places selector
235 q->setAutoFillBackground(false);
236
237 if (placesModel != nullptr) {
238 m_placesSelector = new KUrlNavigatorPlacesSelector(q, placesModel);
239 q->connect(m_placesSelector, &KUrlNavigatorPlacesSelector::placeActivated, q, &KUrlNavigator::setLocationUrl);
240 q->connect(m_placesSelector, &KUrlNavigatorPlacesSelector::tabRequested, q, &KUrlNavigator::tabRequested);
241
242 auto updateContentFunc = [this]() {
243 updateContent();
244 };
245 q->connect(placesModel, &KFilePlacesModel::rowsInserted, q, updateContentFunc);
246 q->connect(placesModel, &KFilePlacesModel::rowsRemoved, q, updateContentFunc);
247 q->connect(placesModel, &KFilePlacesModel::dataChanged, q, updateContentFunc);
248 }
249
250 // create scheme combo
251 m_schemes = new KUrlNavigatorSchemeCombo(QString(), q);
252 q->connect(m_schemes, &KUrlNavigatorSchemeCombo::activated, q, [this](const QString &schene) {
253 slotSchemeChanged(schene);
254 });
255
256 // create drop down button for accessing all paths of the URL
257 m_dropDownButton = new KUrlNavigatorDropDownButton(q);
258 m_dropDownButton->setForegroundRole(QPalette::WindowText);
259 m_dropDownButton->installEventFilter(q);
260 q->connect(m_dropDownButton, &KUrlNavigatorDropDownButton::clicked, q, [this]() {
261 openPathSelectorMenu();
262 });
263
264 // initialize the path box of the traditional view
265 m_pathBox = new KUrlComboBox(KUrlComboBox::Directories, true, q);
266 m_pathBox->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
267 m_pathBox->installEventFilter(q);
268
269 KUrlCompletion *kurlCompletion = new KUrlCompletion(KUrlCompletion::DirCompletion);
270 m_pathBox->setCompletionObject(kurlCompletion);
271 m_pathBox->setAutoDeleteCompletionObject(true);
272
273 // TODO KF6: remove this QOverload, only KUrlComboBox::returnPressed(const QString &) will remain
274 q->connect(m_pathBox, &KUrlComboBox::returnPressed, q, [this]() {
275 slotReturnPressed();
276 });
278 q->connect(m_pathBox, &QComboBox::editTextChanged, q, [this](const QString &text) {
279 slotPathBoxChanged(text);
280 });
281
282 m_badgeWidgetContainer = new QWidget(q);
283 auto badgeLayout = new QHBoxLayout(m_badgeWidgetContainer);
284 badgeLayout->setContentsMargins(0, 0, 0, 0);
285
286 // create toggle button which allows to switch between
287 // the breadcrumb and traditional view
288 m_toggleEditableMode = new KUrlNavigatorToggleButton(q);
289 m_toggleEditableMode->installEventFilter(q);
290 m_toggleEditableMode->setMinimumWidth(20);
291 q->connect(m_toggleEditableMode, &KUrlNavigatorToggleButton::clicked, q, [this]() {
292 slotToggleEditableButtonPressed();
293 });
294
295 if (m_placesSelector != nullptr) {
296 m_layout->addWidget(m_placesSelector);
297 }
298 m_layout->addWidget(m_schemes);
299 m_layout->addWidget(m_dropDownButton);
300 m_layout->addWidget(m_pathBox, 1);
301 m_layout->addWidget(m_badgeWidgetContainer);
302 m_layout->addWidget(m_toggleEditableMode);
303
304 q->setContextMenuPolicy(Qt::CustomContextMenu);
305 q->connect(q, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) {
306 openContextMenu(pos);
307 });
308}
309
310void KUrlNavigatorPrivate::appendWidget(QWidget *widget, int stretch)
311{
312 // insert to the left of: m_badgeWidgetContainer, m_toggleEditableMode
313 m_layout->insertWidget(m_layout->count() - 2, widget, stretch);
314}
315
316void KUrlNavigatorPrivate::slotApplyUrl(QUrl url)
317{
318 // Parts of the following code have been taken from the class KateFileSelector
319 // located in kate/app/katefileselector.hpp of Kate.
320 // SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
321 // SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
322 // SPDX-FileCopyrightText: 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
323
324 // For example "desktop:/" _not_ "desktop:", see the comment in slotSchemeChanged()
325 if (!url.isEmpty() && url.path().isEmpty() && KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) {
326 url.setPath(QStringLiteral("/"));
327 }
328
329 const auto urlStr = url.toString();
330 QStringList urls = m_pathBox->urls();
331 urls.removeAll(urlStr);
332 urls.prepend(urlStr);
333 m_pathBox->setUrls(urls, KUrlComboBox::RemoveBottom);
334
335 q->setLocationUrl(url);
336 // The URL might have been adjusted by KUrlNavigator::setUrl(), hence
337 // synchronize the result in the path box.
338 m_pathBox->setUrl(q->locationUrl());
339}
340
341std::optional<QUrl> KUrlNavigatorPrivate::checkFilters(const QString &text)
342{
343 KUriFilterData filteredData(text);
344 filteredData.setCheckForExecutables(false);
345 // Using kshorturifilter to fix up e.g. "ftp.kde.org" ---> "ftp://ftp.kde.org"
346 const auto filtersList = QStringList{QStringLiteral("kshorturifilter")};
347 const bool wasFiltered = KUriFilter::self()->filterUri(filteredData, filtersList);
348 if (wasFiltered) {
349 return filteredData.uri(); // The text was filtered
350 }
351 return std::nullopt;
352}
353
354void KUrlNavigatorPrivate::applyUncommittedUrl(ApplyUrlMethod method)
355{
356 const QString text = m_pathBox->currentText().trimmed();
357 QUrl url = q->locationUrl();
358
359 auto applyUrl = [this, method](const QUrl &url) {
360 switch (method) {
361 case ApplyUrlMethod::Apply:
362 slotApplyUrl(url);
363 break;
364 case ApplyUrlMethod::Tab:
365 Q_EMIT q->tabRequested(url);
366 break;
367 case ApplyUrlMethod::ActiveTab:
368 Q_EMIT q->activeTabRequested(url);
369 break;
370 case ApplyUrlMethod::NewWindow:
371 Q_EMIT q->newWindowRequested(url);
372 break;
373 }
374 };
375
376 // Using the stat job below, check if the url and text match a local dir; but first
377 // handle a special case where "url" is empty in the unittests which use
378 // KUrlNavigator::setLocationUrl(QUrl()); in practice (e.g. in Dolphin, or KFileWidget),
379 // locationUrl() is never empty
380 if (url.isEmpty() && !text.isEmpty()) {
381 if (const auto filteredUrl = checkFilters(text); filteredUrl) {
382 applyUrl(*filteredUrl);
383 return;
384 }
385 }
386
387 // Treat absolute paths as absolute paths.
388 // Relative paths get appended to the current path.
389 if (text.startsWith(QLatin1Char('/'))) {
390 url.setPath(text);
391 } else {
392 url.setPath(Utils::concatPaths(url.path(), text));
393 }
394
395 // Dirs and symlinks to dirs
396 constexpr auto details = KIO::StatBasic | KIO::StatResolveSymlink;
397 auto *job = KIO::stat(url, KIO::StatJob::DestinationSide, details, KIO::HideProgressInfo);
398 q->connect(job, &KJob::result, q, [this, job, text, applyUrl]() {
399 // If there is a dir matching "text" relative to the current url, use that, e.g.:
400 // - typing "bar" while at "/path/to/foo" ---> "/path/to/foo/bar/"
401 // - typing ".config" while at "/home/foo" ---> "/home/foo/.config"
402 if (!job->error() && job->statResult().isDir()) {
403 applyUrl(job->url());
404 return;
405 }
406
407 // Check if text matches a URI filter
408 if (const auto filteredUrl = checkFilters(text); filteredUrl) {
409 applyUrl(*filteredUrl);
410 return;
411 }
412
413 // ... otherwise fallback to whatever QUrl::fromUserInput() returns
414 applyUrl(QUrl::fromUserInput(text));
415 });
416}
417
418void KUrlNavigatorPrivate::slotReturnPressed()
419{
420 const auto keyboardModifiers = QApplication::keyboardModifiers();
421
422 if (keyboardModifiers & Qt::AltModifier) {
423 if (keyboardModifiers & Qt::ShiftModifier) {
424 applyUncommittedUrl(ApplyUrlMethod::Tab);
425 } else {
426 applyUncommittedUrl(ApplyUrlMethod::ActiveTab);
427 }
428 } else if (keyboardModifiers & Qt::ShiftModifier) {
429 applyUncommittedUrl(ApplyUrlMethod::NewWindow);
430 } else {
431 applyUncommittedUrl(ApplyUrlMethod::Apply);
432
433 Q_EMIT q->returnPressed();
434 }
435
436 if (keyboardModifiers & Qt::ControlModifier) {
437 // Pressing Ctrl+Return automatically switches back to the breadcrumb mode.
438 // The switch must be done asynchronously, as we are in the context of the
439 // editor.
440 auto switchModeFunc = [this]() {
441 switchToBreadcrumbMode();
442 };
444 }
445}
446
447void KUrlNavigatorPrivate::slotSchemeChanged(const QString &scheme)
448{
449 Q_ASSERT(m_editable);
450
451 QUrl url;
452 url.setScheme(scheme);
453 if (KProtocolInfo::protocolClass(scheme) == QLatin1String(":local")) {
454 // E.g. "file:/" or "desktop:/", _not_ "file:" or "desktop:" respectively.
455 // This is the more expected behaviour, "file:somedir" treats somedir as
456 // a path relative to current dir; file:/somedir is an absolute path to /somedir.
457 url.setPath(QStringLiteral("/"));
458 } else {
459 // With no authority set we'll get e.g. "ftp:" instead of "ftp://".
460 // We want the latter, so let's set an empty authority.
461 url.setAuthority(QString());
462 }
463
464 m_pathBox->setEditUrl(url);
465}
466
467void KUrlNavigatorPrivate::openPathSelectorMenu()
468{
469 if (m_navButtons.count() <= 0) {
470 return;
471 }
472
473 const QUrl firstVisibleUrl = m_navButtons.constFirst()->url();
474
475 QString spacer;
476 QPointer<QMenu> popup = new QMenu(q);
477
478 auto *popupFilter = new KUrlNavigatorPathSelectorEventFilter(popup.data());
479 q->connect(popupFilter, &KUrlNavigatorPathSelectorEventFilter::tabRequested, q, &KUrlNavigator::tabRequested);
480 popup->installEventFilter(popupFilter);
481
482 const QUrl placeUrl = retrievePlaceUrl();
483 int idx = placeUrl.path().count(QLatin1Char('/')); // idx points to the first directory
484 // after the place path
485
486 const QString path = m_coreUrlNavigator->locationUrl(m_coreUrlNavigator->historyIndex()).path();
487 QString dirName = path.section(QLatin1Char('/'), idx, idx);
488 if (dirName.isEmpty()) {
489 if (placeUrl.isLocalFile()) {
490 dirName = QStringLiteral("/");
491 } else {
492 dirName = placeUrl.toDisplayString();
493 }
494 }
495 do {
496 const QString text = spacer + dirName;
497
498 QAction *action = new QAction(text, popup);
499 const QUrl currentUrl = buttonUrl(idx);
500 if (currentUrl == firstVisibleUrl) {
501 popup->addSeparator();
502 }
503 action->setData(QVariant(currentUrl.toString()));
504 popup->addAction(action);
505
506 ++idx;
507 spacer.append(QLatin1String(" "));
508 dirName = path.section(QLatin1Char('/'), idx, idx);
509 } while (!dirName.isEmpty());
510
511 const QPoint pos = q->mapToGlobal(m_dropDownButton->geometry().bottomRight());
512 const QAction *activatedAction = popup->exec(pos);
513 if (activatedAction != nullptr) {
514 const QUrl url(activatedAction->data().toString());
515 q->setLocationUrl(url);
516 }
517
518 // Delete the menu, unless it has been deleted in its own nested event loop already.
519 if (popup) {
520 popup->deleteLater();
521 }
522}
523
524void KUrlNavigatorPrivate::slotToggleEditableButtonPressed()
525{
526 if (m_editable) {
527 applyUncommittedUrl(ApplyUrlMethod::Apply);
528 }
529
530 switchView();
531}
532
533void KUrlNavigatorPrivate::switchView()
534{
535 m_toggleEditableMode->setFocus();
536 m_editable = !m_editable;
537 m_toggleEditableMode->setChecked(m_editable);
538 updateContent();
539 if (q->isUrlEditable()) {
540 m_pathBox->setFocus();
541 }
542
544 Q_EMIT q->editableStateChanged(m_editable);
545}
546
547void KUrlNavigatorPrivate::dropUrls(const QUrl &destination, QDropEvent *event, KUrlNavigatorButton *dropButton)
548{
549 if (event->mimeData()->hasUrls()) {
550 m_dropWidget = qobject_cast<QWidget *>(dropButton);
551 Q_EMIT q->urlsDropped(destination, event);
552 }
553}
554
555void KUrlNavigatorPrivate::slotNavigatorButtonClicked(const QUrl &url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
556{
557 if ((button & Qt::MiddleButton && modifiers & Qt::ShiftModifier) || (button & Qt::LeftButton && modifiers & (Qt::ControlModifier | Qt::ShiftModifier))) {
558 Q_EMIT q->activeTabRequested(url);
559 } else if (button & Qt::MiddleButton || (button & Qt::LeftButton && modifiers & Qt::ControlModifier)) {
560 Q_EMIT q->tabRequested(url);
561 } else if (button & Qt::LeftButton && modifiers & Qt::ShiftModifier) {
562 Q_EMIT q->newWindowRequested(url);
563 } else if (button & Qt::LeftButton) {
564 q->setLocationUrl(url);
565 }
566}
567
568void KUrlNavigatorPrivate::openContextMenu(const QPoint &p)
569{
570 q->setActive(true);
571
572 QPointer<QMenu> popup = new QMenu(q);
573
574 // provide 'Copy' action, which copies the current URL of
575 // the URL navigator into the clipboard
576 QAction *copyAction = popup->addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy"));
577
578 // provide 'Paste' action, which copies the current clipboard text
579 // into the URL navigator
580 QAction *pasteAction = popup->addAction(QIcon::fromTheme(QStringLiteral("edit-paste")), i18n("Paste"));
581 QClipboard *clipboard = QApplication::clipboard();
582 pasteAction->setEnabled(!clipboard->text().isEmpty());
583
584 popup->addSeparator();
585
586 // We are checking whether the signal is connected because it's odd to have a tab entry even
587 // if it's not supported, like in the case of the open dialog
590 if (isTabSignal || isWindowSignal) {
591 auto it = std::find_if(m_navButtons.cbegin(), m_navButtons.cend(), [&p](const KUrlNavigatorButton *button) {
592 return button->geometry().contains(p);
593 });
594 if (it != m_navButtons.cend()) {
595 const auto *button = *it;
596 const QUrl url = button->url();
597 const QString text = button->text();
598
599 if (isTabSignal) {
600 QAction *openInTab = popup->addAction(QIcon::fromTheme(QStringLiteral("tab-new")), i18nc("@item:inmenu", "Open \"%1\" in New Tab", text));
601 q->connect(openInTab, &QAction::triggered, q, [this, url]() {
602 Q_EMIT q->tabRequested(url);
603 });
604 }
605
606 if (isWindowSignal) {
607 QAction *openInWindow =
608 popup->addAction(QIcon::fromTheme(QStringLiteral("window-new")), i18nc("@item:inmenu", "Open \"%1\" in New Window", text));
609 q->connect(openInWindow, &QAction::triggered, q, [this, url]() {
610 Q_EMIT q->newWindowRequested(url);
611 });
612 }
613 }
614 }
615
616 // provide radiobuttons for toggling between the edit and the navigation mode
617 QAction *editAction = popup->addAction(i18n("Edit"));
618 editAction->setCheckable(true);
619
620 QAction *navigateAction = popup->addAction(i18n("Navigate"));
621 navigateAction->setCheckable(true);
622
623 QActionGroup *modeGroup = new QActionGroup(popup);
624 modeGroup->addAction(editAction);
625 modeGroup->addAction(navigateAction);
626 if (q->isUrlEditable()) {
627 editAction->setChecked(true);
628 } else {
629 navigateAction->setChecked(true);
630 }
631
632 popup->addSeparator();
633
634 // allow showing of the full path
635 QAction *showFullPathAction = popup->addAction(i18n("Show Full Path"));
636 showFullPathAction->setCheckable(true);
637 showFullPathAction->setChecked(q->showFullPath());
638
639 QAction *activatedAction = popup->exec(QCursor::pos());
640 if (activatedAction == copyAction) {
641 QMimeData *mimeData = new QMimeData();
643 clipboard->setMimeData(mimeData);
644 } else if (activatedAction == pasteAction) {
645 q->setLocationUrl(QUrl::fromUserInput(clipboard->text()));
646 } else if (activatedAction == editAction) {
647 q->setUrlEditable(true);
648 } else if (activatedAction == navigateAction) {
649 q->setUrlEditable(false);
650 } else if (activatedAction == showFullPathAction) {
651 q->setShowFullPath(showFullPathAction->isChecked());
652 }
653
654 // Delete the menu, unless it has been deleted in its own nested event loop already.
655 if (popup) {
656 popup->deleteLater();
657 }
658}
659
660void KUrlNavigatorPrivate::slotPathBoxChanged(const QString &text)
661{
662 if (text.isEmpty()) {
663 const QString scheme = q->locationUrl().scheme();
664 m_schemes->setScheme(scheme);
665 if (m_supportedSchemes.count() != 1) {
666 m_schemes->show();
667 updateTabOrder();
668 }
669 } else {
670 m_schemes->hide();
671 updateTabOrder();
672 }
673}
674
675void KUrlNavigatorPrivate::updateContent()
676{
677 const QUrl currentUrl = q->locationUrl();
678 if (m_placesSelector != nullptr) {
679 m_placesSelector->updateSelection(currentUrl);
680 }
681
682 if (m_editable) {
683 m_schemes->hide();
684 m_dropDownButton->hide();
685 m_badgeWidgetContainer->hide();
686
687 deleteButtons();
688 m_toggleEditableMode->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
690
691 m_pathBox->show();
692 m_pathBox->setUrl(currentUrl);
693
694 q->setTabOrder(m_pathBox, m_toggleEditableMode); // Fixes order for the first time switchView() is called.
695 updateTabOrder();
696 } else {
697 m_pathBox->hide();
698 m_badgeWidgetContainer->show();
699
700 m_schemes->hide();
701
702 m_toggleEditableMode->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
704
705 // Calculate the start index for the directories that should be shown as buttons
706 // and create the buttons
707 QUrl placeUrl;
708 if ((m_placesSelector != nullptr) && !m_showFullPath) {
709 placeUrl = m_placesSelector->selectedPlaceUrl();
710 }
711
712 if (!placeUrl.isValid()) {
713 placeUrl = retrievePlaceUrl();
714 }
715 QString placePath = Utils::trailingSlashRemoved(placeUrl.path());
716
717 const int startIndex = placePath.count(QLatin1Char('/'));
718 updateButtons(startIndex);
719 }
720}
721
722void KUrlNavigatorPrivate::updateButtons(int startIndex)
723{
724 QUrl currentUrl = q->locationUrl();
725 if (!currentUrl.isValid()) { // QFileDialog::setDirectory not called yet
726 return;
727 }
728
729 const QString path = currentUrl.path();
730
731 const int oldButtonCount = m_navButtons.count();
732
733 int idx = startIndex;
734 bool hasNext = true;
735 do {
736 const bool createButton = (idx - startIndex) >= oldButtonCount;
737 const bool isFirstButton = (idx == startIndex);
738 const QString dirName = path.section(QLatin1Char('/'), idx, idx);
739 hasNext = isFirstButton || !dirName.isEmpty();
740 if (hasNext) {
741 KUrlNavigatorButton *button = nullptr;
742 if (createButton) {
743 button = new KUrlNavigatorButton(buttonUrl(idx), q);
744 button->installEventFilter(q);
745 button->setForegroundRole(QPalette::WindowText);
746 q->connect(button, &KUrlNavigatorButton::urlsDroppedOnNavButton, q, [this, button](const QUrl &destination, QDropEvent *event) {
747 dropUrls(destination, event, button);
748 });
749
750 auto activatedFunc = [this](const QUrl &url, Qt::MouseButton btn, Qt::KeyboardModifiers modifiers) {
751 slotNavigatorButtonClicked(url, btn, modifiers);
752 };
753 q->connect(button, &KUrlNavigatorButton::navigatorButtonActivated, q, activatedFunc);
754
755 q->connect(button, &KUrlNavigatorButton::finishedTextResolving, q, [this]() {
756 updateButtonVisibility();
757 });
758
759 appendWidget(button);
760 } else {
761 button = m_navButtons[idx - startIndex];
762 button->setUrl(buttonUrl(idx));
763 }
764
765 if (isFirstButton) {
766 button->setText(firstButtonText());
767 }
768 button->setActive(q->isActive());
769
770 if (createButton) {
771 if (!isFirstButton) {
772 q->setTabOrder(m_navButtons.constLast(), button);
773 }
774 m_navButtons.append(button);
775 }
776
777 ++idx;
778 button->setActiveSubDirectory(path.section(QLatin1Char('/'), idx, idx));
779 }
780 } while (hasNext);
781
782 // delete buttons which are not used anymore
783 const int newButtonCount = idx - startIndex;
784 if (newButtonCount < oldButtonCount) {
785 const auto itBegin = m_navButtons.begin() + newButtonCount;
786 const auto itEnd = m_navButtons.end();
787 for (auto it = itBegin; it != itEnd; ++it) {
788 auto *navBtn = *it;
789 navBtn->hide();
790 navBtn->deleteLater();
791 }
792 m_navButtons.erase(itBegin, itEnd);
793 }
794
795 m_dropDownButton->setToolTip(xi18nc("@info:tooltip for button. 1 is path",
796 "Go to any location on the path <filename>%1</filename>",
798 .replace(QStringLiteral("///"), QStringLiteral("/")));
799 updateButtonVisibility();
800}
801
802void KUrlNavigatorPrivate::updateButtonVisibility()
803{
804 if (m_editable) {
805 return;
806 }
807
808 const int buttonsCount = m_navButtons.count();
809 if (buttonsCount == 0) {
810 m_dropDownButton->hide();
811 return;
812 }
813
814 // Subtract all widgets from the available width, that must be shown anyway
815 int availableWidth = q->width() - m_toggleEditableMode->minimumWidth();
816
817 availableWidth -= m_badgeWidgetContainer->width();
818
819 if ((m_placesSelector != nullptr) && m_placesSelector->isVisible()) {
820 availableWidth -= m_placesSelector->width();
821 }
822
823 if ((m_schemes != nullptr) && m_schemes->isVisible()) {
824 availableWidth -= m_schemes->width();
825 }
826
827 // Check whether buttons must be hidden at all...
828 int requiredButtonWidth = 0;
829 for (const auto *button : std::as_const(m_navButtons)) {
830 requiredButtonWidth += button->minimumWidth();
831 }
832
833 if (requiredButtonWidth > availableWidth) {
834 // At least one button must be hidden. This implies that the
835 // drop-down button must get visible, which again decreases the
836 // available width.
837 availableWidth -= m_dropDownButton->width();
838 }
839
840 // Hide buttons...
841 bool isLastButton = true;
842 bool hasHiddenButtons = false;
843 QList<KUrlNavigatorButton *> buttonsToShow;
844 for (auto it = m_navButtons.crbegin(); it != m_navButtons.crend(); ++it) {
845 KUrlNavigatorButton *button = *it;
846 availableWidth -= button->minimumWidth();
847 if ((availableWidth <= 0) && !isLastButton) {
848 button->hide();
849 hasHiddenButtons = true;
850 } else {
851 // Don't show the button immediately, as setActive()
852 // might change the size and a relayout gets triggered
853 // after showing the button. So the showing of all buttons
854 // is postponed until all buttons have the correct
855 // activation state.
856 buttonsToShow.append(button);
857 }
858 isLastButton = false;
859 }
860
861 // All buttons have the correct activation state and
862 // can be shown now
863 for (KUrlNavigatorButton *button : std::as_const(buttonsToShow)) {
864 button->show();
865 }
866
867 if (hasHiddenButtons) {
868 m_dropDownButton->show();
869 } else {
870 // Check whether going upwards is possible. If this is the case, show the drop-down button.
871 QUrl url(m_navButtons.front()->url());
872 const bool visible = !url.matches(KIO::upUrl(url), QUrl::StripTrailingSlash) //
873 && url.scheme() != QLatin1String("baloosearch") //
874 && url.scheme() != QLatin1String("filenamesearch");
875 m_dropDownButton->setVisible(visible);
876 }
877
878 updateTabOrder();
879}
880
881void KUrlNavigatorPrivate::updateTabOrder()
882{
883 QMultiMap<int, QWidget *> visibleChildrenSortedByX;
884 const auto childWidgets = q->findChildren<QWidget *>();
885 for (auto childWidget : childWidgets) {
886 if (childWidget->isVisible()) {
887 if (q->layoutDirection() == Qt::LeftToRight) {
888 visibleChildrenSortedByX.insert(childWidget->x(), childWidget); // sort ascending
889 } else {
890 visibleChildrenSortedByX.insert(-childWidget->x(), childWidget); // sort descending
891 }
892 }
893 }
894 if (visibleChildrenSortedByX.isEmpty()) {
895 return;
896 }
897 q->setFocusProxy(visibleChildrenSortedByX.first());
898 auto it = visibleChildrenSortedByX.begin();
899 auto nextIt = ++visibleChildrenSortedByX.begin();
900 while (nextIt != visibleChildrenSortedByX.end()) {
901 q->setTabOrder(*it, *nextIt);
902 it++;
903 nextIt++;
904 }
905}
906
907QString KUrlNavigatorPrivate::firstButtonText() const
908{
909 QString text;
910
911 // The first URL navigator button should get the name of the
912 // place instead of the directory name
913 if ((m_placesSelector != nullptr) && !m_showFullPath) {
914 text = m_placesSelector->selectedPlaceText();
915 }
916
917 const QUrl currentUrl = q->locationUrl();
918
919 if (text.isEmpty()) {
920 if (currentUrl.isLocalFile()) {
921#ifdef Q_OS_WIN
922 text = currentUrl.path().length() > 1 ? currentUrl.path().left(2) : QDir::rootPath();
923#else
924 text = QStringLiteral("/");
925#endif
926 }
927 }
928
929 if (text.isEmpty()) {
930 if (currentUrl.path().isEmpty() || currentUrl.path() == QLatin1Char('/')) {
931 QUrlQuery query(currentUrl);
932 text = query.queryItemValue(QStringLiteral("title"), QUrl::FullyDecoded);
933 }
934 }
935
936 if (text.isEmpty()) {
937 text = currentUrl.scheme() + QLatin1Char(':');
938 if (!currentUrl.host().isEmpty()) {
939 text += QLatin1Char(' ') + currentUrl.host();
940 }
941 }
942
943 return text;
944}
945
946QUrl KUrlNavigatorPrivate::buttonUrl(int index) const
947{
948 if (index < 0) {
949 index = 0;
950 }
951
952 // Keep scheme, hostname etc. as this is needed for e. g. browsing
953 // FTP directories
954 QUrl url = q->locationUrl();
955 QString path = url.path();
956
957 if (!path.isEmpty()) {
958 if (index == 0) {
959 // prevent the last "/" from being stripped
960 // or we end up with an empty path
961#ifdef Q_OS_WIN
962 path = path.length() > 1 ? path.left(2) : QDir::rootPath();
963#else
964 path = QStringLiteral("/");
965#endif
966 } else {
967 path = path.section(QLatin1Char('/'), 0, index);
968 }
969 }
970
971 url.setPath(path);
972 return url;
973}
974
975void KUrlNavigatorPrivate::switchToBreadcrumbMode()
976{
977 q->setUrlEditable(false);
978}
979
980void KUrlNavigatorPrivate::deleteButtons()
981{
982 for (KUrlNavigatorButton *button : std::as_const(m_navButtons)) {
983 button->hide();
984 button->deleteLater();
985 }
986 m_navButtons.clear();
987}
988
989QUrl KUrlNavigatorPrivate::retrievePlaceUrl() const
990{
991 QUrl currentUrl = q->locationUrl();
992 currentUrl.setPath(QString());
993 return currentUrl;
994}
995
996// ------------------------------------------------------------------------------------------------
997
999 : KUrlNavigator(nullptr, QUrl{}, parent)
1000{
1001}
1002
1004 : QWidget(parent)
1005 , d(new KUrlNavigatorPrivate(url, this, placesModel))
1006{
1007 const int minHeight = d->m_pathBox->sizeHint().height();
1008 setMinimumHeight(minHeight);
1009
1010 setMinimumWidth(100);
1011
1012 d->updateContent();
1013}
1014
1015KUrlNavigator::~KUrlNavigator()
1016{
1017 d->m_dropDownButton->removeEventFilter(this);
1018 d->m_pathBox->removeEventFilter(this);
1019 for (auto *button : std::as_const(d->m_navButtons)) {
1020 button->removeEventFilter(this);
1021 }
1022}
1023
1024QUrl KUrlNavigator::locationUrl(int historyIndex) const
1025{
1026 return d->m_coreUrlNavigator->locationUrl(historyIndex);
1027}
1028
1030{
1031 auto current = d->m_coreUrlNavigator->locationState().value<KUrlNavigatorData>();
1032 current.state = state;
1033 d->m_coreUrlNavigator->saveLocationState(QVariant::fromValue(current));
1034}
1035
1037{
1038 return d->m_coreUrlNavigator->locationState(historyIndex).value<KUrlNavigatorData>().state;
1039}
1040
1042{
1043 return d->m_coreUrlNavigator->goBack();
1044}
1045
1047{
1048 return d->m_coreUrlNavigator->goForward();
1049}
1050
1052{
1053 return d->m_coreUrlNavigator->goUp();
1054}
1055
1057{
1058 if (d->m_homeUrl.isEmpty() || !d->m_homeUrl.isValid()) {
1060 } else {
1061 setLocationUrl(d->m_homeUrl);
1062 }
1063}
1064
1066{
1067 d->m_homeUrl = url;
1068}
1069
1070QUrl KUrlNavigator::homeUrl() const
1071{
1072 return d->m_homeUrl;
1073}
1074
1076{
1077 if (d->m_editable != editable) {
1078 d->switchView();
1079 }
1080}
1081
1083{
1084 return d->m_editable;
1085}
1086
1088{
1089 if (d->m_showFullPath != show) {
1090 d->m_showFullPath = show;
1091 d->updateContent();
1092 }
1093}
1094
1096{
1097 return d->m_showFullPath;
1098}
1099
1101{
1102 if (active != d->m_active) {
1103 d->m_active = active;
1104
1105 d->m_dropDownButton->setActive(active);
1106 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) {
1107 button->setActive(active);
1108 }
1109
1110 update();
1111 if (active) {
1112 Q_EMIT activated();
1113 }
1114 }
1115}
1116
1118{
1119 return d->m_active;
1120}
1121
1123{
1124 if (visible == d->m_showPlacesSelector) {
1125 return;
1126 }
1127
1128 if (visible && (d->m_placesSelector == nullptr)) {
1129 // the places selector cannot get visible as no
1130 // places model is available
1131 return;
1132 }
1133
1134 d->m_showPlacesSelector = visible;
1135 d->m_placesSelector->setVisible(visible);
1136 d->updateTabOrder();
1137}
1138
1140{
1141 return d->m_showPlacesSelector;
1142}
1143
1145{
1146 KUriFilterData filteredData(d->m_pathBox->currentText().trimmed());
1147 filteredData.setCheckForExecutables(false);
1148 if (KUriFilter::self()->filterUri(filteredData, QStringList{QStringLiteral("kshorturifilter")})) {
1149 return filteredData.uri();
1150 } else {
1151 return QUrl::fromUserInput(filteredData.typedString());
1152 }
1153}
1154
1156{
1157 d->m_coreUrlNavigator->setCurrentLocationUrl(newUrl);
1158
1159 d->updateContent();
1160
1162}
1163
1165{
1166 setActive(true);
1167}
1168
1170{
1171 if (isUrlEditable()) {
1172 d->m_pathBox->setFocus();
1173 } else {
1175 }
1176}
1177
1179{
1180 if (isUrlEditable() && (event->key() == Qt::Key_Escape)) {
1181 setUrlEditable(false);
1182 } else {
1184 }
1185}
1186
1188{
1190}
1191
1193{
1194 if (event->button() == Qt::MiddleButton) {
1196 }
1198}
1199
1201{
1202 if (event->button() == Qt::MiddleButton) {
1203 const QRect bounds = d->m_toggleEditableMode->geometry();
1204 if (bounds.contains(event->pos())) {
1205 // The middle mouse button has been clicked above the
1206 // toggle-editable-mode-button. Paste the clipboard content
1207 // as location URL.
1208 QClipboard *clipboard = QApplication::clipboard();
1209 const QMimeData *mimeData = clipboard->mimeData();
1210 if (mimeData->hasText()) {
1211 const QString text = mimeData->text();
1213 }
1214 }
1215 }
1217}
1218
1220{
1221 QTimer::singleShot(0, this, [this]() {
1222 d->updateButtonVisibility();
1223 });
1225}
1226
1228{
1229 setActive(true);
1231}
1232
1233bool KUrlNavigator::eventFilter(QObject *watched, QEvent *event)
1234{
1235 switch (event->type()) {
1236 case QEvent::FocusIn:
1237 if (watched == d->m_pathBox) {
1239 setFocus();
1240 }
1241 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) {
1242 button->setShowMnemonic(true);
1243 }
1244 break;
1245
1246 case QEvent::FocusOut:
1247 for (KUrlNavigatorButton *button : std::as_const(d->m_navButtons)) {
1248 button->setShowMnemonic(false);
1249 }
1250 break;
1251
1252 // Avoid the "Properties" action from triggering instead of new tab.
1254 auto *keyEvent = static_cast<QKeyEvent *>(event);
1255 if ((keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return)
1256 && (keyEvent->modifiers() & Qt::AltModifier || keyEvent->modifiers() & Qt::ShiftModifier)) {
1257 event->accept();
1258 return true;
1259 }
1260 break;
1261 }
1262
1263 default:
1264 break;
1265 }
1266
1267 return QWidget::eventFilter(watched, event);
1268}
1269
1271{
1272 return d->m_coreUrlNavigator->historySize();
1273}
1274
1276{
1277 return d->m_coreUrlNavigator->historyIndex();
1278}
1279
1281{
1282 return d->m_pathBox;
1283}
1284
1286{
1287 d->m_supportedSchemes = schemes;
1288 d->m_schemes->setSupportedSchemes(d->m_supportedSchemes);
1289}
1290
1292{
1293 return d->m_supportedSchemes;
1294}
1295
1297{
1298 return d->m_dropWidget;
1299}
1300
1301void KUrlNavigator::setShowHiddenFolders(bool showHiddenFolders)
1302{
1303 d->m_subfolderOptions.showHidden = showHiddenFolders;
1304}
1305
1307{
1308 return d->m_subfolderOptions.showHidden;
1309}
1310
1311void KUrlNavigator::setSortHiddenFoldersLast(bool sortHiddenFoldersLast)
1312{
1313 d->m_subfolderOptions.sortHiddenLast = sortHiddenFoldersLast;
1314}
1315
1317{
1318 return d->m_subfolderOptions.sortHiddenLast;
1319}
1320
1322{
1323 QWidget *oldWidget = badgeWidget();
1324 if (oldWidget) {
1325 if (widget == oldWidget) {
1326 return;
1327 }
1328 d->m_badgeWidgetContainer->layout()->replaceWidget(oldWidget, widget);
1329 oldWidget->deleteLater();
1330 } else {
1331 d->m_badgeWidgetContainer->layout()->addWidget(widget);
1332 }
1333}
1334
1336{
1337 QLayoutItem *item = d->m_badgeWidgetContainer->layout()->itemAt(0);
1338 if (item) {
1339 return item->widget();
1340 } else {
1341 return nullptr;
1342 }
1343}
1344
1345#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.
void result(KJob *job)
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...
Definition kurifilter.h:153
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 setBadgeWidget(QWidget *widget)
Puts widget to the right of the breadcrumb.
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
int historyIndex() 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().
QWidget * badgeWidget() const
Returns the badge widget set by setBadgeWidget().
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 isActive() const
int historySize() 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 xi18nc(const char *context, const char *text, const TYPE &arg...)
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)
std::optional< QSqlQuery > query(const QString &queryStatement)
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition statjob.cpp:203
KIOCORE_EXPORT QUrl upUrl(const QUrl &url)
This function is useful to implement the "Up" button in a file manager for example.
Definition global.cpp:238
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
Definition job_base.h:251
@ StatBasic
Filename, access, type, size, linkdest.
Definition global.h:255
@ StatResolveSymlink
Resolve symlinks.
Definition global.h:261
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)
void setCheckable(bool)
void setChecked(bool)
QVariant data() const const
void setEnabled(bool)
void setData(const QVariant &data)
void triggered(bool checked)
QAction * addAction(QAction *action)
virtual int count() const const override
void insertWidget(int index, QWidget *widget, int stretch, Qt::Alignment alignment)
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)
QPoint pos()
QString homePath()
QString rootPath()
QClipboard * clipboard()
Qt::KeyboardModifiers keyboardModifiers()
QIcon fromTheme(const QString &name)
virtual QWidget * widget() const const
void append(QList< T > &&value)
iterator begin()
const_iterator cbegin() const const
const_iterator cend() const const
void clear()
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 end()
iterator erase(const_iterator begin, const_iterator end)
reference front()
void prepend(parameter_type value)
qsizetype removeAll(const AT &t)
QMetaMethod fromSignal(PointerToMemberFunction signal)
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
bool hasText() const const
void setText(const QString &text)
QString text() const const
iterator begin()
iterator end()
T & first()
iterator insert(const Key &key, const T &value)
bool isEmpty() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
virtual bool eventFilter(QObject *watched, QEvent *event)
QList< T > findChildren(Qt::FindChildOptions options) const const
bool isSignalConnected(const QMetaMethod &signal) const const
void removeEventFilter(QObject *obj)
T * data() const const
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 & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QueuedConnection
CustomContextMenu
Key_Escape
typedef KeyboardModifiers
LeftToRight
MouseButton
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
FullyDecoded
PreferLocalFile
QUrl fromLocalFile(const QString &localFile)
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
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
void customContextMenuRequested(const QPoint &pos)
virtual bool event(QEvent *event) override
void hide()
virtual void keyPressEvent(QKeyEvent *event)
virtual void keyReleaseEvent(QKeyEvent *event)
QPoint mapToGlobal(const QPoint &pos) const const
void setMinimumHeight(int minh)
void setMinimumWidth(int minw)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
virtual void resizeEvent(QResizeEvent *event)
void setFocus()
void setFocusProxy(QWidget *w)
void setTabOrder(QWidget *first, QWidget *second)
void show()
void setSizePolicy(QSizePolicy)
void update()
virtual void wheelEvent(QWheelEvent *event)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:58:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.