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

KDE's Doxygen guidelines are available online.