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