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

KDE's Doxygen guidelines are available online.