1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999, 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
4 SPDX-FileCopyrightText: 2013 Teo Mrnjavac <teo@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "kurlrequester.h"
10#include "../utils_p.h"
11#include "kio_widgets_debug.h"
12
13#include <KComboBox>
14#include <KDragWidgetDecorator>
15#include <KLineEdit>
16#include <KLocalizedString>
17#include <kprotocolmanager.h>
18#include <kurlcompletion.h>
19
20#include <QAccessibleWidget>
21#include <QAction>
22#include <QApplication>
23#include <QDrag>
24#include <QEvent>
25#include <QHBoxLayout>
26#include <QKeySequence>
27#include <QMenu>
28#include <QMimeData>
29
30#include <private/qguiapplication_p.h>
31#include <qpa/qplatformtheme.h>
32
33class AccessibleLabelFromParentLineEdit : public QAccessibleWidget
34{
35public:
36 AccessibleLabelFromParentLineEdit(KLineEdit *parent)
37 : QAccessibleWidget{parent}
38 {}
39
40 QList<std::pair<QAccessibleInterface *, QAccessible::Relation>> relations(QAccessible::Relation match = QAccessible::AllRelations) const override
41 {
42 auto relations = QAccessibleWidget::relations(match);
43 constexpr auto labelType = QAccessible::Label;
44 if (match & labelType) {
45 for (const auto &relation : relations) {
46 if (relation.second == labelType) {
47 return relations;
48 }
49 }
50 const QAccessibleInterface *parentInterface = QAccessible::queryAccessibleInterface(parentObject());
51 const auto parentLabelledRelation = parentInterface->relations(match: labelType);
52 relations.append(l: parentLabelledRelation);
53 }
54 return relations;
55 }
56};
57
58QAccessibleInterface *accessibleInterfaceFactory(const QString &key, QObject *object)
59{
60 Q_UNUSED(key)
61 if (KLineEdit *lineEdit = qobject_cast<KLineEdit *>(object)) {
62 return new AccessibleLabelFromParentLineEdit(lineEdit);
63 }
64 return nullptr;
65};
66
67class KUrlDragPushButton : public QPushButton
68{
69 Q_OBJECT
70public:
71 explicit KUrlDragPushButton(QWidget *parent)
72 : QPushButton(parent)
73 {
74 new DragDecorator(this);
75 }
76 ~KUrlDragPushButton() override
77 {
78 }
79
80 void setURL(const QUrl &url)
81 {
82 m_urls.clear();
83 m_urls.append(t: url);
84 }
85
86private:
87 class DragDecorator : public KDragWidgetDecoratorBase
88 {
89 public:
90 explicit DragDecorator(KUrlDragPushButton *button)
91 : KDragWidgetDecoratorBase(button)
92 , m_button(button)
93 {
94 }
95
96 protected:
97 QDrag *dragObject() override
98 {
99 if (m_button->m_urls.isEmpty()) {
100 return nullptr;
101 }
102
103 QDrag *drag = new QDrag(m_button);
104 QMimeData *mimeData = new QMimeData;
105 mimeData->setUrls(m_button->m_urls);
106 drag->setMimeData(mimeData);
107 return drag;
108 }
109
110 private:
111 KUrlDragPushButton *m_button;
112 };
113
114 QList<QUrl> m_urls;
115};
116
117class Q_DECL_HIDDEN KUrlRequester::KUrlRequesterPrivate
118{
119public:
120 explicit KUrlRequesterPrivate(KUrlRequester *parent)
121 : m_fileDialogModeWasDirAndFile(false)
122 , m_parent(parent)
123 , edit(nullptr)
124 , combo(nullptr)
125 , fileDialogMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly)
126 , fileDialogAcceptMode(QFileDialog::AcceptOpen)
127 {
128 }
129
130 ~KUrlRequesterPrivate()
131 {
132 delete myCompletion;
133 delete myFileDialog;
134 }
135
136 void init();
137
138 void setText(const QString &text)
139 {
140 if (combo) {
141 if (combo->isEditable()) {
142 combo->setEditText(text);
143 } else {
144 int i = combo->findText(text);
145 if (i == -1) {
146 combo->addItem(atext: text);
147 combo->setCurrentIndex(combo->count() - 1);
148 } else {
149 combo->setCurrentIndex(i);
150 }
151 }
152 } else {
153 edit->setText(text);
154 }
155 }
156
157 void connectSignals(KUrlRequester *receiver)
158 {
159 if (combo) {
160 connect(sender: combo, signal: &QComboBox::currentTextChanged, context: receiver, slot: &KUrlRequester::textChanged);
161 connect(sender: combo, signal: &QComboBox::editTextChanged, context: receiver, slot: &KUrlRequester::textEdited);
162
163 connect(sender: combo, signal: &KComboBox::returnPressed, context: receiver, slot: &KUrlRequester::returnPressed);
164 } else if (edit) {
165 connect(sender: edit, signal: &QLineEdit::textChanged, context: receiver, slot: &KUrlRequester::textChanged);
166 connect(sender: edit, signal: &QLineEdit::textEdited, context: receiver, slot: &KUrlRequester::textEdited);
167
168 connect(sender: edit, signal: qOverload<>(&QLineEdit::returnPressed), context: receiver, slot: [this]() {
169 m_parent->Q_EMIT returnPressed(text: QString{});
170 });
171
172 if (auto kline = qobject_cast<KLineEdit *>(object: edit)) {
173 connect(sender: kline, signal: &KLineEdit::returnKeyPressed, context: receiver, slot: &KUrlRequester::returnPressed);
174 }
175 }
176 }
177
178 void setCompletionObject(KCompletion *comp)
179 {
180 if (combo) {
181 combo->setCompletionObject(completionObject: comp);
182 } else {
183 edit->setCompletionObject(comp);
184 }
185 }
186
187 void updateCompletionStartDir(const QUrl &newStartDir)
188 {
189 myCompletion->setDir(newStartDir);
190 }
191
192 QString text() const
193 {
194 return combo ? combo->currentText() : edit->text();
195 }
196
197 /*
198 * replaces ~user or $FOO, if necessary
199 * if text() is a relative path, make it absolute using startDir()
200 */
201 QUrl url() const
202 {
203 const QString txt = text();
204 KUrlCompletion *comp;
205 if (combo) {
206 comp = qobject_cast<KUrlCompletion *>(object: combo->completionObject());
207 } else {
208 comp = qobject_cast<KUrlCompletion *>(object: edit->completionObject());
209 }
210
211 QString enteredPath;
212 if (comp) {
213 enteredPath = comp->replacedPath(text: txt);
214 } else {
215 enteredPath = txt;
216 }
217
218 if (Utils::isAbsoluteLocalPath(path: enteredPath)) {
219 return QUrl::fromLocalFile(localfile: enteredPath);
220 }
221
222 const QUrl enteredUrl = QUrl(enteredPath); // absolute or relative
223 if (enteredUrl.isRelative() && !txt.isEmpty()) {
224 QUrl finalUrl(m_startDir);
225 finalUrl.setPath(path: Utils::concatPaths(path1: finalUrl.path(), path2: enteredPath));
226 return finalUrl;
227 } else {
228 return enteredUrl;
229 }
230 }
231
232 static void applyFileMode(QFileDialog *dlg, KFile::Modes m, QFileDialog::AcceptMode acceptMode)
233 {
234 QFileDialog::FileMode fileMode;
235 bool dirsOnly = false;
236 if (m & KFile::Directory) {
237 fileMode = QFileDialog::Directory;
238 if ((m & KFile::File) == 0 && (m & KFile::Files) == 0) {
239 dirsOnly = true;
240 }
241 } else if (m & KFile::Files && m & KFile::ExistingOnly) {
242 fileMode = QFileDialog::ExistingFiles;
243 } else if (m & KFile::File && m & KFile::ExistingOnly) {
244 fileMode = QFileDialog::ExistingFile;
245 } else {
246 fileMode = QFileDialog::AnyFile;
247 }
248
249 dlg->setFileMode(fileMode);
250 dlg->setAcceptMode(acceptMode);
251 dlg->setOption(option: QFileDialog::ShowDirsOnly, on: dirsOnly);
252 }
253
254 QUrl getDirFromFileDialog(const QUrl &openUrl) const
255 {
256 return QFileDialog::getExistingDirectoryUrl(parent: m_parent, caption: QString(), dir: openUrl, options: QFileDialog::ShowDirsOnly);
257 }
258
259 void createFileDialog()
260 {
261 // Creates the fileDialog if it doesn't exist yet
262 QFileDialog *dlg = m_parent->fileDialog();
263
264 if (!url().isEmpty() && !url().isRelative()) {
265 QUrl u(url());
266 // If we won't be able to list it (e.g. http), then don't try :)
267 if (KProtocolManager::supportsListing(url: u)) {
268 dlg->selectUrl(url: u);
269 }
270 } else {
271 dlg->setDirectoryUrl(m_startDir);
272 }
273
274 dlg->setAcceptMode(fileDialogAcceptMode);
275
276 // Update the file dialog window modality
277 if (dlg->windowModality() != fileDialogModality) {
278 dlg->setWindowModality(fileDialogModality);
279 }
280
281 if (fileDialogModality == Qt::NonModal) {
282 dlg->show();
283 } else {
284 dlg->exec();
285 }
286 }
287
288 // slots
289 void slotUpdateUrl();
290 void slotOpenDialog();
291 void slotFileDialogAccepted();
292
293 QUrl m_startDir;
294 bool m_startDirCustomized;
295 bool m_fileDialogModeWasDirAndFile;
296 KUrlRequester *const m_parent; // TODO: rename to 'q'
297 KLineEdit *edit;
298 KComboBox *combo;
299 KFile::Modes fileDialogMode;
300 QFileDialog::AcceptMode fileDialogAcceptMode;
301 QStringList nameFilters;
302 QStringList mimeTypeFilters;
303 KEditListWidget::CustomEditor editor;
304 KUrlDragPushButton *myButton;
305 QFileDialog *myFileDialog;
306 KUrlCompletion *myCompletion;
307 Qt::WindowModality fileDialogModality;
308};
309
310KUrlRequester::KUrlRequester(QWidget *editWidget, QWidget *parent)
311 : QWidget(parent)
312 , d(new KUrlRequesterPrivate(this))
313{
314 // must have this as parent
315 editWidget->setParent(this);
316 d->combo = qobject_cast<KComboBox *>(object: editWidget);
317 d->edit = qobject_cast<KLineEdit *>(object: editWidget);
318 if (d->edit) {
319 d->edit->setClearButtonEnabled(true);
320 }
321
322 d->init();
323}
324
325KUrlRequester::KUrlRequester(QWidget *parent)
326 : QWidget(parent)
327 , d(new KUrlRequesterPrivate(this))
328{
329 d->init();
330}
331
332KUrlRequester::KUrlRequester(const QUrl &url, QWidget *parent)
333 : QWidget(parent)
334 , d(new KUrlRequesterPrivate(this))
335{
336 d->init();
337 setUrl(url);
338}
339
340KUrlRequester::~KUrlRequester()
341{
342 QWidget *widget = d->combo ? static_cast<QWidget *>(d->combo) : static_cast<QWidget *>(d->edit);
343 widget->removeEventFilter(obj: this);
344}
345
346void KUrlRequester::KUrlRequesterPrivate::init()
347{
348 myFileDialog = nullptr;
349 fileDialogModality = Qt::ApplicationModal;
350
351 if (!combo && !edit) {
352 edit = new KLineEdit(m_parent);
353 edit->setClearButtonEnabled(true);
354 }
355
356 QWidget *widget = combo ? static_cast<QWidget *>(combo) : static_cast<QWidget *>(edit);
357
358 QHBoxLayout *topLayout = new QHBoxLayout(m_parent);
359 topLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0);
360 topLayout->setSpacing(-1); // use default spacing
361 topLayout->addWidget(widget);
362
363 myButton = new KUrlDragPushButton(m_parent);
364 myButton->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
365 int buttonSize = myButton->sizeHint().expandedTo(otherSize: widget->sizeHint()).height();
366 myButton->setFixedSize(w: buttonSize, h: buttonSize);
367 myButton->setToolTip(i18n("Open file dialog"));
368
369 connect(sender: myButton, signal: &KUrlDragPushButton::pressed, context: m_parent, slot: [this]() {
370 slotUpdateUrl();
371 });
372
373 widget->installEventFilter(filterObj: m_parent);
374 m_parent->setFocusProxy(widget);
375 m_parent->setFocusPolicy(Qt::StrongFocus);
376 topLayout->addWidget(myButton);
377
378 connectSignals(receiver: m_parent);
379 connect(sender: myButton, signal: &KUrlDragPushButton::clicked, context: m_parent, slot: [this]() {
380 slotOpenDialog();
381 });
382
383 m_startDir = QUrl::fromLocalFile(localfile: QDir::currentPath());
384 m_startDirCustomized = false;
385
386 myCompletion = new KUrlCompletion();
387 updateCompletionStartDir(newStartDir: m_startDir);
388
389 setCompletionObject(myCompletion);
390
391 QAction *openAction = new QAction(m_parent);
392 openAction->setShortcut(QKeySequence::Open);
393 m_parent->connect(sender: openAction, signal: &QAction::triggered, context: m_parent, slot: [this]() {
394 slotOpenDialog();
395 });
396
397 QAccessible::installFactory(accessibleInterfaceFactory);
398}
399
400void KUrlRequester::setUrl(const QUrl &url)
401{
402 d->setText(url.toDisplayString(options: QUrl::PreferLocalFile));
403}
404
405void KUrlRequester::setText(const QString &text)
406{
407 d->setText(text);
408}
409
410void KUrlRequester::setStartDir(const QUrl &startDir)
411{
412 d->m_startDir = startDir;
413 d->m_startDirCustomized = true;
414 d->updateCompletionStartDir(newStartDir: startDir);
415}
416
417void KUrlRequester::changeEvent(QEvent *e)
418{
419 if (e->type() == QEvent::WindowTitleChange) {
420 if (d->myFileDialog) {
421 d->myFileDialog->setWindowTitle(windowTitle());
422 }
423 }
424 QWidget::changeEvent(e);
425}
426
427QUrl KUrlRequester::url() const
428{
429 return d->url();
430}
431
432QUrl KUrlRequester::startDir() const
433{
434 return d->m_startDir;
435}
436
437QString KUrlRequester::text() const
438{
439 return d->text();
440}
441
442void KUrlRequester::KUrlRequesterPrivate::slotOpenDialog()
443{
444 if (myFileDialog) {
445 if (myFileDialog->isVisible()) {
446 // The file dialog is already being shown, raise it and exit
447 myFileDialog->raise();
448 myFileDialog->activateWindow();
449 return;
450 }
451 }
452
453 if (!m_fileDialogModeWasDirAndFile
454 && (((fileDialogMode & KFile::Directory) && !(fileDialogMode & KFile::File)) ||
455 /* catch possible fileDialog()->setMode( KFile::Directory ) changes */
456 (myFileDialog && (myFileDialog->fileMode() == QFileDialog::Directory && myFileDialog->testOption(option: QFileDialog::ShowDirsOnly))))) {
457 const QUrl openUrl = (!m_parent->url().isEmpty() && !m_parent->url().isRelative()) ? m_parent->url() : m_startDir;
458
459 /* FIXME We need a new abstract interface for using KDirSelectDialog in a non-modal way */
460
461 QUrl newUrl;
462 if (fileDialogMode & KFile::LocalOnly) {
463 newUrl = QFileDialog::getExistingDirectoryUrl(parent: m_parent, caption: QString(), dir: openUrl, options: QFileDialog::ShowDirsOnly, supportedSchemes: QStringList() << QStringLiteral("file"));
464 } else {
465 newUrl = getDirFromFileDialog(openUrl);
466 }
467
468 if (newUrl.isValid()) {
469 m_parent->setUrl(newUrl);
470 Q_EMIT m_parent->urlSelected(url());
471 }
472 } else {
473 Q_EMIT m_parent->openFileDialog(m_parent);
474
475 if (((fileDialogMode & KFile::Directory) && (fileDialogMode & KFile::File)) || m_fileDialogModeWasDirAndFile) {
476 QMenu *dirOrFileMenu = new QMenu();
477 QAction *fileAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("File"));
478 QAction *dirAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Directory"));
479 dirOrFileMenu->addAction(action: fileAction);
480 dirOrFileMenu->addAction(action: dirAction);
481
482 connect(sender: fileAction, signal: &QAction::triggered, slot: [this]() {
483 fileDialogMode = KFile::File;
484 applyFileMode(dlg: m_parent->fileDialog(), m: fileDialogMode, acceptMode: fileDialogAcceptMode);
485 m_fileDialogModeWasDirAndFile = true;
486 createFileDialog();
487 });
488
489 connect(sender: dirAction, signal: &QAction::triggered, slot: [this]() {
490 fileDialogMode = KFile::Directory;
491 applyFileMode(dlg: m_parent->fileDialog(), m: fileDialogMode, acceptMode: fileDialogAcceptMode);
492 m_fileDialogModeWasDirAndFile = true;
493 createFileDialog();
494 });
495
496 dirOrFileMenu->exec(pos: m_parent->mapToGlobal(QPoint(m_parent->width(), m_parent->height())));
497
498 return;
499 }
500
501 createFileDialog();
502 }
503}
504
505void KUrlRequester::KUrlRequesterPrivate::slotFileDialogAccepted()
506{
507 if (!myFileDialog) {
508 return;
509 }
510
511 const QUrl newUrl = myFileDialog->selectedUrls().constFirst();
512 if (newUrl.isValid()) {
513 m_parent->setUrl(newUrl);
514 Q_EMIT m_parent->urlSelected(url());
515 // remember url as defaultStartDir and update startdir for autocompletion
516 if (newUrl.isLocalFile() && !m_startDirCustomized) {
517 m_startDir = newUrl.adjusted(options: QUrl::RemoveFilename);
518 updateCompletionStartDir(newStartDir: m_startDir);
519 }
520 }
521}
522
523void KUrlRequester::setMode(KFile::Modes mode)
524{
525 Q_ASSERT((mode & KFile::Files) == 0);
526 d->fileDialogMode = mode;
527 if ((mode & KFile::Directory) && !(mode & KFile::File)) {
528 d->myCompletion->setMode(KUrlCompletion::DirCompletion);
529 }
530
531 if (d->myFileDialog) {
532 d->applyFileMode(dlg: d->myFileDialog, m: mode, acceptMode: d->fileDialogAcceptMode);
533 }
534}
535
536KFile::Modes KUrlRequester::mode() const
537{
538 return d->fileDialogMode;
539}
540
541void KUrlRequester::setAcceptMode(QFileDialog::AcceptMode mode)
542{
543 d->fileDialogAcceptMode = mode;
544
545 if (d->myFileDialog) {
546 d->applyFileMode(dlg: d->myFileDialog, m: d->fileDialogMode, acceptMode: mode);
547 }
548}
549
550QFileDialog::AcceptMode KUrlRequester::acceptMode() const
551{
552 return d->fileDialogAcceptMode;
553}
554
555QStringList KUrlRequester::nameFilters() const
556{
557 return d->nameFilters;
558}
559
560void KUrlRequester::setNameFilters(const QStringList &filters)
561{
562 d->nameFilters = filters;
563
564 if (d->myFileDialog) {
565 d->myFileDialog->setNameFilters(d->nameFilters);
566 }
567}
568
569void KUrlRequester::setNameFilter(const QString &filter)
570{
571 if (filter.isEmpty()) {
572 setNameFilters(QStringList());
573 return;
574 }
575
576 // by default use ";;" as separator
577 // if not present, support alternatively "\n" (matching QFileDialog behaviour)
578 // if also not present split() will simply return the string passed in
579 QString separator = QStringLiteral(";;");
580 if (!filter.contains(s: separator)) {
581 separator = QStringLiteral("\n");
582 }
583 setNameFilters(filter.split(sep: separator));
584}
585
586void KUrlRequester::setMimeTypeFilters(const QStringList &mimeTypes)
587{
588 d->mimeTypeFilters = mimeTypes;
589
590 if (d->myFileDialog) {
591 d->myFileDialog->setMimeTypeFilters(d->mimeTypeFilters);
592 }
593 d->myCompletion->setMimeTypeFilters(d->mimeTypeFilters);
594}
595
596QStringList KUrlRequester::mimeTypeFilters() const
597{
598 return d->mimeTypeFilters;
599}
600
601QFileDialog *KUrlRequester::fileDialog() const
602{
603 if (d->myFileDialog
604 && ((d->myFileDialog->fileMode() == QFileDialog::Directory && !(d->fileDialogMode & KFile::Directory))
605 || (d->myFileDialog->fileMode() != QFileDialog::Directory && (d->fileDialogMode & KFile::Directory)))) {
606 delete d->myFileDialog;
607 d->myFileDialog = nullptr;
608 }
609
610 if (!d->myFileDialog) {
611 d->myFileDialog = new QFileDialog(window(), windowTitle());
612 if (!d->mimeTypeFilters.isEmpty()) {
613 QStringList mimeTypeFilters = d->mimeTypeFilters;
614 // The non plasma file dialogs don't have the "All Supported types" feature, so add the "All Files" type for them if more than one
615 // file type type is possible
616 if (mimeTypeFilters.count() > 1 && !mimeTypeFilters.contains(QStringLiteral("application/octet-stream"))
617 && QGuiApplicationPrivate::platformTheme()->name() != QStringLiteral("kde")) {
618 mimeTypeFilters.prepend(QStringLiteral("application/octet-stream"));
619 }
620 d->myFileDialog->setMimeTypeFilters(mimeTypeFilters);
621 } else {
622 d->myFileDialog->setNameFilters(d->nameFilters);
623 }
624
625 d->applyFileMode(dlg: d->myFileDialog, m: d->fileDialogMode, acceptMode: d->fileDialogAcceptMode);
626
627 d->myFileDialog->setWindowModality(d->fileDialogModality);
628 connect(sender: d->myFileDialog, signal: &QFileDialog::accepted, context: this, slot: [this]() {
629 d->slotFileDialogAccepted();
630 });
631 }
632
633 return d->myFileDialog;
634}
635
636void KUrlRequester::clear()
637{
638 d->setText(QString());
639}
640
641KLineEdit *KUrlRequester::lineEdit() const
642{
643 return d->edit;
644}
645
646KComboBox *KUrlRequester::comboBox() const
647{
648 return d->combo;
649}
650
651void KUrlRequester::KUrlRequesterPrivate::slotUpdateUrl()
652{
653 const QUrl visibleUrl = url();
654 QUrl u = visibleUrl;
655 if (visibleUrl.isRelative()) {
656 u = QUrl::fromLocalFile(localfile: QDir::currentPath() + QLatin1Char('/')).resolved(relative: visibleUrl);
657 }
658 myButton->setURL(u);
659}
660
661bool KUrlRequester::eventFilter(QObject *obj, QEvent *ev)
662{
663 if ((d->edit == obj) || (d->combo == obj)) {
664 if ((ev->type() == QEvent::FocusIn) || (ev->type() == QEvent::FocusOut))
665 // Forward focusin/focusout events to the urlrequester; needed by file form element in khtml
666 {
667 QApplication::sendEvent(receiver: this, event: ev);
668 }
669 }
670 return QWidget::eventFilter(watched: obj, event: ev);
671}
672
673QPushButton *KUrlRequester::button() const
674{
675 return d->myButton;
676}
677
678KUrlCompletion *KUrlRequester::completionObject() const
679{
680 return d->myCompletion;
681}
682
683void KUrlRequester::setPlaceholderText(const QString &msg)
684{
685 if (d->edit) {
686 d->edit->setPlaceholderText(msg);
687 }
688}
689
690QString KUrlRequester::placeholderText() const
691{
692 if (d->edit) {
693 return d->edit->placeholderText();
694 } else {
695 return QString();
696 }
697}
698
699Qt::WindowModality KUrlRequester::fileDialogModality() const
700{
701 return d->fileDialogModality;
702}
703
704void KUrlRequester::setFileDialogModality(Qt::WindowModality modality)
705{
706 d->fileDialogModality = modality;
707}
708
709const KEditListWidget::CustomEditor &KUrlRequester::customEditor()
710{
711 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
712
713 KLineEdit *edit = d->edit;
714 if (!edit && d->combo) {
715 edit = qobject_cast<KLineEdit *>(object: d->combo->lineEdit());
716 }
717
718#ifndef NDEBUG
719 if (!edit) {
720 qCWarning(KIO_WIDGETS) << "KUrlRequester's lineedit is not a KLineEdit!??\n";
721 }
722#endif
723
724 d->editor.setRepresentationWidget(this);
725 d->editor.setLineEdit(edit);
726 return d->editor;
727}
728
729KUrlComboRequester::KUrlComboRequester(QWidget *parent)
730 : KUrlRequester(new KComboBox(false), parent)
731 , d(nullptr)
732{
733}
734
735#include "kurlrequester.moc"
736#include "moc_kurlrequester.cpp"
737

source code of kio/src/widgets/kurlrequester.cpp