File indexing completed on 2024-04-28 07:44:39

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999, 2000, 2001 Carsten Pfeiffer <pfeiffer@kde.org>
0004     SPDX-FileCopyrightText: 2013 Teo Mrnjavac <teo@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "kurlrequester.h"
0010 #include "../utils_p.h"
0011 #include "kio_widgets_debug.h"
0012 
0013 #include <KComboBox>
0014 #include <KDragWidgetDecorator>
0015 #include <KLineEdit>
0016 #include <KLocalizedString>
0017 #include <kprotocolmanager.h>
0018 #include <kurlcompletion.h>
0019 
0020 #include <QAction>
0021 #include <QApplication>
0022 #include <QDrag>
0023 #include <QEvent>
0024 #include <QHBoxLayout>
0025 #include <QKeySequence>
0026 #include <QMenu>
0027 #include <QMimeData>
0028 
0029 class KUrlDragPushButton : public QPushButton
0030 {
0031     Q_OBJECT
0032 public:
0033     explicit KUrlDragPushButton(QWidget *parent)
0034         : QPushButton(parent)
0035     {
0036         new DragDecorator(this);
0037     }
0038     ~KUrlDragPushButton() override
0039     {
0040     }
0041 
0042     void setURL(const QUrl &url)
0043     {
0044         m_urls.clear();
0045         m_urls.append(url);
0046     }
0047 
0048 private:
0049     class DragDecorator : public KDragWidgetDecoratorBase
0050     {
0051     public:
0052         explicit DragDecorator(KUrlDragPushButton *button)
0053             : KDragWidgetDecoratorBase(button)
0054             , m_button(button)
0055         {
0056         }
0057 
0058     protected:
0059         QDrag *dragObject() override
0060         {
0061             if (m_button->m_urls.isEmpty()) {
0062                 return nullptr;
0063             }
0064 
0065             QDrag *drag = new QDrag(m_button);
0066             QMimeData *mimeData = new QMimeData;
0067             mimeData->setUrls(m_button->m_urls);
0068             drag->setMimeData(mimeData);
0069             return drag;
0070         }
0071 
0072     private:
0073         KUrlDragPushButton *m_button;
0074     };
0075 
0076     QList<QUrl> m_urls;
0077 };
0078 
0079 class Q_DECL_HIDDEN KUrlRequester::KUrlRequesterPrivate
0080 {
0081 public:
0082     explicit KUrlRequesterPrivate(KUrlRequester *parent)
0083         : m_fileDialogModeWasDirAndFile(false)
0084         , m_parent(parent)
0085         , edit(nullptr)
0086         , combo(nullptr)
0087         , fileDialogMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly)
0088         , fileDialogAcceptMode(QFileDialog::AcceptOpen)
0089     {
0090     }
0091 
0092     ~KUrlRequesterPrivate()
0093     {
0094         delete myCompletion;
0095         delete myFileDialog;
0096     }
0097 
0098     void init();
0099 
0100     void setText(const QString &text)
0101     {
0102         if (combo) {
0103             if (combo->isEditable()) {
0104                 combo->setEditText(text);
0105             } else {
0106                 int i = combo->findText(text);
0107                 if (i == -1) {
0108                     combo->addItem(text);
0109                     combo->setCurrentIndex(combo->count() - 1);
0110                 } else {
0111                     combo->setCurrentIndex(i);
0112                 }
0113             }
0114         } else {
0115             edit->setText(text);
0116         }
0117     }
0118 
0119     void connectSignals(KUrlRequester *receiver)
0120     {
0121         if (combo) {
0122             connect(combo, &QComboBox::currentTextChanged, receiver, &KUrlRequester::textChanged);
0123             connect(combo, &QComboBox::editTextChanged, receiver, &KUrlRequester::textEdited);
0124 
0125             connect(combo, &KComboBox::returnPressed, receiver, &KUrlRequester::returnPressed);
0126         } else if (edit) {
0127             connect(edit, &QLineEdit::textChanged, receiver, &KUrlRequester::textChanged);
0128             connect(edit, &QLineEdit::textEdited, receiver, &KUrlRequester::textEdited);
0129 
0130             connect(edit, qOverload<>(&QLineEdit::returnPressed), receiver, [this]() {
0131                 m_parent->Q_EMIT returnPressed(QString{});
0132             });
0133 
0134             if (auto kline = qobject_cast<KLineEdit *>(edit)) {
0135                 connect(kline, &KLineEdit::returnKeyPressed, receiver, &KUrlRequester::returnPressed);
0136             }
0137         }
0138     }
0139 
0140     void setCompletionObject(KCompletion *comp)
0141     {
0142         if (combo) {
0143             combo->setCompletionObject(comp);
0144         } else {
0145             edit->setCompletionObject(comp);
0146         }
0147     }
0148 
0149     void updateCompletionStartDir(const QUrl &newStartDir)
0150     {
0151         myCompletion->setDir(newStartDir);
0152     }
0153 
0154     QString text() const
0155     {
0156         return combo ? combo->currentText() : edit->text();
0157     }
0158 
0159     /**
0160      * replaces ~user or $FOO, if necessary
0161      * if text() is a relative path, make it absolute using startDir()
0162      */
0163     QUrl url() const
0164     {
0165         const QString txt = text();
0166         KUrlCompletion *comp;
0167         if (combo) {
0168             comp = qobject_cast<KUrlCompletion *>(combo->completionObject());
0169         } else {
0170             comp = qobject_cast<KUrlCompletion *>(edit->completionObject());
0171         }
0172 
0173         QString enteredPath;
0174         if (comp) {
0175             enteredPath = comp->replacedPath(txt);
0176         } else {
0177             enteredPath = txt;
0178         }
0179 
0180         if (Utils::isAbsoluteLocalPath(enteredPath)) {
0181             return QUrl::fromLocalFile(enteredPath);
0182         }
0183 
0184         const QUrl enteredUrl = QUrl(enteredPath); // absolute or relative
0185         if (enteredUrl.isRelative() && !txt.isEmpty()) {
0186             QUrl finalUrl(m_startDir);
0187             finalUrl.setPath(Utils::concatPaths(finalUrl.path(), enteredPath));
0188             return finalUrl;
0189         } else {
0190             return enteredUrl;
0191         }
0192     }
0193 
0194     static void applyFileMode(QFileDialog *dlg, KFile::Modes m, QFileDialog::AcceptMode acceptMode)
0195     {
0196         QFileDialog::FileMode fileMode;
0197         bool dirsOnly = false;
0198         if (m & KFile::Directory) {
0199             fileMode = QFileDialog::Directory;
0200             if ((m & KFile::File) == 0 && (m & KFile::Files) == 0) {
0201                 dirsOnly = true;
0202             }
0203         } else if (m & KFile::Files && m & KFile::ExistingOnly) {
0204             fileMode = QFileDialog::ExistingFiles;
0205         } else if (m & KFile::File && m & KFile::ExistingOnly) {
0206             fileMode = QFileDialog::ExistingFile;
0207         } else {
0208             fileMode = QFileDialog::AnyFile;
0209         }
0210 
0211         dlg->setFileMode(fileMode);
0212         dlg->setAcceptMode(acceptMode);
0213         dlg->setOption(QFileDialog::ShowDirsOnly, dirsOnly);
0214     }
0215 
0216     QUrl getDirFromFileDialog(const QUrl &openUrl) const
0217     {
0218         return QFileDialog::getExistingDirectoryUrl(m_parent, QString(), openUrl, QFileDialog::ShowDirsOnly);
0219     }
0220 
0221     void createFileDialog()
0222     {
0223         // Creates the fileDialog if it doesn't exist yet
0224         QFileDialog *dlg = m_parent->fileDialog();
0225 
0226         if (!url().isEmpty() && !url().isRelative()) {
0227             QUrl u(url());
0228             // If we won't be able to list it (e.g. http), then don't try :)
0229             if (KProtocolManager::supportsListing(u)) {
0230                 dlg->selectUrl(u);
0231             }
0232         } else {
0233             dlg->setDirectoryUrl(m_startDir);
0234         }
0235 
0236         dlg->setAcceptMode(fileDialogAcceptMode);
0237 
0238         // Update the file dialog window modality
0239         if (dlg->windowModality() != fileDialogModality) {
0240             dlg->setWindowModality(fileDialogModality);
0241         }
0242 
0243         if (fileDialogModality == Qt::NonModal) {
0244             dlg->show();
0245         } else {
0246             dlg->exec();
0247         }
0248     }
0249 
0250     // slots
0251     void slotUpdateUrl();
0252     void slotOpenDialog();
0253     void slotFileDialogAccepted();
0254 
0255     QUrl m_startDir;
0256     bool m_startDirCustomized;
0257     bool m_fileDialogModeWasDirAndFile;
0258     KUrlRequester *const m_parent; // TODO: rename to 'q'
0259     KLineEdit *edit;
0260     KComboBox *combo;
0261     KFile::Modes fileDialogMode;
0262     QFileDialog::AcceptMode fileDialogAcceptMode;
0263     QStringList nameFilters;
0264     QStringList mimeTypeFilters;
0265     KEditListWidget::CustomEditor editor;
0266     KUrlDragPushButton *myButton;
0267     QFileDialog *myFileDialog;
0268     KUrlCompletion *myCompletion;
0269     Qt::WindowModality fileDialogModality;
0270 };
0271 
0272 KUrlRequester::KUrlRequester(QWidget *editWidget, QWidget *parent)
0273     : QWidget(parent)
0274     , d(new KUrlRequesterPrivate(this))
0275 {
0276     // must have this as parent
0277     editWidget->setParent(this);
0278     d->combo = qobject_cast<KComboBox *>(editWidget);
0279     d->edit = qobject_cast<KLineEdit *>(editWidget);
0280     if (d->edit) {
0281         d->edit->setClearButtonEnabled(true);
0282     }
0283 
0284     d->init();
0285 }
0286 
0287 KUrlRequester::KUrlRequester(QWidget *parent)
0288     : QWidget(parent)
0289     , d(new KUrlRequesterPrivate(this))
0290 {
0291     d->init();
0292 }
0293 
0294 KUrlRequester::KUrlRequester(const QUrl &url, QWidget *parent)
0295     : QWidget(parent)
0296     , d(new KUrlRequesterPrivate(this))
0297 {
0298     d->init();
0299     setUrl(url);
0300 }
0301 
0302 KUrlRequester::~KUrlRequester()
0303 {
0304     QWidget *widget = d->combo ? static_cast<QWidget *>(d->combo) : static_cast<QWidget *>(d->edit);
0305     widget->removeEventFilter(this);
0306 }
0307 
0308 void KUrlRequester::KUrlRequesterPrivate::init()
0309 {
0310     myFileDialog = nullptr;
0311     fileDialogModality = Qt::ApplicationModal;
0312 
0313     if (!combo && !edit) {
0314         edit = new KLineEdit(m_parent);
0315         edit->setClearButtonEnabled(true);
0316     }
0317 
0318     QWidget *widget = combo ? static_cast<QWidget *>(combo) : static_cast<QWidget *>(edit);
0319 
0320     QHBoxLayout *topLayout = new QHBoxLayout(m_parent);
0321     topLayout->setContentsMargins(0, 0, 0, 0);
0322     topLayout->setSpacing(-1); // use default spacing
0323     topLayout->addWidget(widget);
0324 
0325     myButton = new KUrlDragPushButton(m_parent);
0326     myButton->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0327     int buttonSize = myButton->sizeHint().expandedTo(widget->sizeHint()).height();
0328     myButton->setFixedSize(buttonSize, buttonSize);
0329     myButton->setToolTip(i18n("Open file dialog"));
0330 
0331     connect(myButton, &KUrlDragPushButton::pressed, m_parent, [this]() {
0332         slotUpdateUrl();
0333     });
0334 
0335     widget->installEventFilter(m_parent);
0336     m_parent->setFocusProxy(widget);
0337     m_parent->setFocusPolicy(Qt::StrongFocus);
0338     topLayout->addWidget(myButton);
0339 
0340     connectSignals(m_parent);
0341     connect(myButton, &KUrlDragPushButton::clicked, m_parent, [this]() {
0342         slotOpenDialog();
0343     });
0344 
0345     m_startDir = QUrl::fromLocalFile(QDir::currentPath());
0346     m_startDirCustomized = false;
0347 
0348     myCompletion = new KUrlCompletion();
0349     updateCompletionStartDir(m_startDir);
0350 
0351     setCompletionObject(myCompletion);
0352 
0353     QAction *openAction = new QAction(m_parent);
0354     openAction->setShortcut(QKeySequence::Open);
0355     m_parent->connect(openAction, &QAction::triggered, m_parent, [this]() {
0356         slotOpenDialog();
0357     });
0358 }
0359 
0360 void KUrlRequester::setUrl(const QUrl &url)
0361 {
0362     d->setText(url.toDisplayString(QUrl::PreferLocalFile));
0363 }
0364 
0365 void KUrlRequester::setText(const QString &text)
0366 {
0367     d->setText(text);
0368 }
0369 
0370 void KUrlRequester::setStartDir(const QUrl &startDir)
0371 {
0372     d->m_startDir = startDir;
0373     d->m_startDirCustomized = true;
0374     d->updateCompletionStartDir(startDir);
0375 }
0376 
0377 void KUrlRequester::changeEvent(QEvent *e)
0378 {
0379     if (e->type() == QEvent::WindowTitleChange) {
0380         if (d->myFileDialog) {
0381             d->myFileDialog->setWindowTitle(windowTitle());
0382         }
0383     }
0384     QWidget::changeEvent(e);
0385 }
0386 
0387 QUrl KUrlRequester::url() const
0388 {
0389     return d->url();
0390 }
0391 
0392 QUrl KUrlRequester::startDir() const
0393 {
0394     return d->m_startDir;
0395 }
0396 
0397 QString KUrlRequester::text() const
0398 {
0399     return d->text();
0400 }
0401 
0402 void KUrlRequester::KUrlRequesterPrivate::slotOpenDialog()
0403 {
0404     if (myFileDialog) {
0405         if (myFileDialog->isVisible()) {
0406             // The file dialog is already being shown, raise it and exit
0407             myFileDialog->raise();
0408             myFileDialog->activateWindow();
0409             return;
0410         }
0411     }
0412 
0413     if (!m_fileDialogModeWasDirAndFile
0414         && (((fileDialogMode & KFile::Directory) && !(fileDialogMode & KFile::File)) ||
0415             /* catch possible fileDialog()->setMode( KFile::Directory ) changes */
0416             (myFileDialog && (myFileDialog->fileMode() == QFileDialog::Directory && myFileDialog->testOption(QFileDialog::ShowDirsOnly))))) {
0417         const QUrl openUrl = (!m_parent->url().isEmpty() && !m_parent->url().isRelative()) ? m_parent->url() : m_startDir;
0418 
0419         /* FIXME We need a new abstract interface for using KDirSelectDialog in a non-modal way */
0420 
0421         QUrl newUrl;
0422         if (fileDialogMode & KFile::LocalOnly) {
0423             newUrl = QFileDialog::getExistingDirectoryUrl(m_parent, QString(), openUrl, QFileDialog::ShowDirsOnly, QStringList() << QStringLiteral("file"));
0424         } else {
0425             newUrl = getDirFromFileDialog(openUrl);
0426         }
0427 
0428         if (newUrl.isValid()) {
0429             m_parent->setUrl(newUrl);
0430             Q_EMIT m_parent->urlSelected(url());
0431         }
0432     } else {
0433         Q_EMIT m_parent->openFileDialog(m_parent);
0434 
0435         if (((fileDialogMode & KFile::Directory) && (fileDialogMode & KFile::File)) || m_fileDialogModeWasDirAndFile) {
0436             QMenu *dirOrFileMenu = new QMenu();
0437             QAction *fileAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("File"));
0438             QAction *dirAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Directory"));
0439             dirOrFileMenu->addAction(fileAction);
0440             dirOrFileMenu->addAction(dirAction);
0441 
0442             connect(fileAction, &QAction::triggered, [this]() {
0443                 fileDialogMode = KFile::File;
0444                 applyFileMode(m_parent->fileDialog(), fileDialogMode, fileDialogAcceptMode);
0445                 m_fileDialogModeWasDirAndFile = true;
0446                 createFileDialog();
0447             });
0448 
0449             connect(dirAction, &QAction::triggered, [this]() {
0450                 fileDialogMode = KFile::Directory;
0451                 applyFileMode(m_parent->fileDialog(), fileDialogMode, fileDialogAcceptMode);
0452                 m_fileDialogModeWasDirAndFile = true;
0453                 createFileDialog();
0454             });
0455 
0456             dirOrFileMenu->exec(m_parent->mapToGlobal(QPoint(m_parent->width(), m_parent->height())));
0457 
0458             return;
0459         }
0460 
0461         createFileDialog();
0462     }
0463 }
0464 
0465 void KUrlRequester::KUrlRequesterPrivate::slotFileDialogAccepted()
0466 {
0467     if (!myFileDialog) {
0468         return;
0469     }
0470 
0471     const QUrl newUrl = myFileDialog->selectedUrls().constFirst();
0472     if (newUrl.isValid()) {
0473         m_parent->setUrl(newUrl);
0474         Q_EMIT m_parent->urlSelected(url());
0475         // remember url as defaultStartDir and update startdir for autocompletion
0476         if (newUrl.isLocalFile() && !m_startDirCustomized) {
0477             m_startDir = newUrl.adjusted(QUrl::RemoveFilename);
0478             updateCompletionStartDir(m_startDir);
0479         }
0480     }
0481 }
0482 
0483 void KUrlRequester::setMode(KFile::Modes mode)
0484 {
0485     Q_ASSERT((mode & KFile::Files) == 0);
0486     d->fileDialogMode = mode;
0487     if ((mode & KFile::Directory) && !(mode & KFile::File)) {
0488         d->myCompletion->setMode(KUrlCompletion::DirCompletion);
0489     }
0490 
0491     if (d->myFileDialog) {
0492         d->applyFileMode(d->myFileDialog, mode, d->fileDialogAcceptMode);
0493     }
0494 }
0495 
0496 KFile::Modes KUrlRequester::mode() const
0497 {
0498     return d->fileDialogMode;
0499 }
0500 
0501 void KUrlRequester::setAcceptMode(QFileDialog::AcceptMode mode)
0502 {
0503     d->fileDialogAcceptMode = mode;
0504 
0505     if (d->myFileDialog) {
0506         d->applyFileMode(d->myFileDialog, d->fileDialogMode, mode);
0507     }
0508 }
0509 
0510 QFileDialog::AcceptMode KUrlRequester::acceptMode() const
0511 {
0512     return d->fileDialogAcceptMode;
0513 }
0514 
0515 QStringList KUrlRequester::nameFilters() const
0516 {
0517     return d->nameFilters;
0518 }
0519 
0520 void KUrlRequester::setNameFilters(const QStringList &filters)
0521 {
0522     d->nameFilters = filters;
0523 
0524     if (d->myFileDialog) {
0525         d->myFileDialog->setNameFilters(d->nameFilters);
0526     }
0527 }
0528 
0529 void KUrlRequester::setNameFilter(const QString &filter)
0530 {
0531     if (filter.isEmpty()) {
0532         setNameFilters(QStringList());
0533         return;
0534     }
0535 
0536     // by default use ";;" as separator
0537     // if not present, support alternatively "\n" (matching QFileDialog behaviour)
0538     // if also not present split() will simply return the string passed in
0539     QString separator = QStringLiteral(";;");
0540     if (!filter.contains(separator)) {
0541         separator = QStringLiteral("\n");
0542     }
0543     setNameFilters(filter.split(separator));
0544 }
0545 
0546 void KUrlRequester::setMimeTypeFilters(const QStringList &mimeTypes)
0547 {
0548     d->mimeTypeFilters = mimeTypes;
0549 
0550     if (d->myFileDialog) {
0551         d->myFileDialog->setMimeTypeFilters(d->mimeTypeFilters);
0552     }
0553     d->myCompletion->setMimeTypeFilters(d->mimeTypeFilters);
0554 }
0555 
0556 QStringList KUrlRequester::mimeTypeFilters() const
0557 {
0558     return d->mimeTypeFilters;
0559 }
0560 
0561 QFileDialog *KUrlRequester::fileDialog() const
0562 {
0563     if (d->myFileDialog
0564         && ((d->myFileDialog->fileMode() == QFileDialog::Directory && !(d->fileDialogMode & KFile::Directory))
0565             || (d->myFileDialog->fileMode() != QFileDialog::Directory && (d->fileDialogMode & KFile::Directory)))) {
0566         delete d->myFileDialog;
0567         d->myFileDialog = nullptr;
0568     }
0569 
0570     if (!d->myFileDialog) {
0571         d->myFileDialog = new QFileDialog(window(), windowTitle());
0572         if (!d->mimeTypeFilters.isEmpty()) {
0573             d->myFileDialog->setMimeTypeFilters(d->mimeTypeFilters);
0574         } else {
0575             d->myFileDialog->setNameFilters(d->nameFilters);
0576         }
0577 
0578         d->applyFileMode(d->myFileDialog, d->fileDialogMode, d->fileDialogAcceptMode);
0579 
0580         d->myFileDialog->setWindowModality(d->fileDialogModality);
0581         connect(d->myFileDialog, &QFileDialog::accepted, this, [this]() {
0582             d->slotFileDialogAccepted();
0583         });
0584     }
0585 
0586     return d->myFileDialog;
0587 }
0588 
0589 void KUrlRequester::clear()
0590 {
0591     d->setText(QString());
0592 }
0593 
0594 KLineEdit *KUrlRequester::lineEdit() const
0595 {
0596     return d->edit;
0597 }
0598 
0599 KComboBox *KUrlRequester::comboBox() const
0600 {
0601     return d->combo;
0602 }
0603 
0604 void KUrlRequester::KUrlRequesterPrivate::slotUpdateUrl()
0605 {
0606     const QUrl visibleUrl = url();
0607     QUrl u = visibleUrl;
0608     if (visibleUrl.isRelative()) {
0609         u = QUrl::fromLocalFile(QDir::currentPath() + QLatin1Char('/')).resolved(visibleUrl);
0610     }
0611     myButton->setURL(u);
0612 }
0613 
0614 bool KUrlRequester::eventFilter(QObject *obj, QEvent *ev)
0615 {
0616     if ((d->edit == obj) || (d->combo == obj)) {
0617         if ((ev->type() == QEvent::FocusIn) || (ev->type() == QEvent::FocusOut))
0618         // Forward focusin/focusout events to the urlrequester; needed by file form element in khtml
0619         {
0620             QApplication::sendEvent(this, ev);
0621         }
0622     }
0623     return QWidget::eventFilter(obj, ev);
0624 }
0625 
0626 QPushButton *KUrlRequester::button() const
0627 {
0628     return d->myButton;
0629 }
0630 
0631 KUrlCompletion *KUrlRequester::completionObject() const
0632 {
0633     return d->myCompletion;
0634 }
0635 
0636 void KUrlRequester::setPlaceholderText(const QString &msg)
0637 {
0638     if (d->edit) {
0639         d->edit->setPlaceholderText(msg);
0640     }
0641 }
0642 
0643 QString KUrlRequester::placeholderText() const
0644 {
0645     if (d->edit) {
0646         return d->edit->placeholderText();
0647     } else {
0648         return QString();
0649     }
0650 }
0651 
0652 Qt::WindowModality KUrlRequester::fileDialogModality() const
0653 {
0654     return d->fileDialogModality;
0655 }
0656 
0657 void KUrlRequester::setFileDialogModality(Qt::WindowModality modality)
0658 {
0659     d->fileDialogModality = modality;
0660 }
0661 
0662 const KEditListWidget::CustomEditor &KUrlRequester::customEditor()
0663 {
0664     setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
0665 
0666     KLineEdit *edit = d->edit;
0667     if (!edit && d->combo) {
0668         edit = qobject_cast<KLineEdit *>(d->combo->lineEdit());
0669     }
0670 
0671 #ifndef NDEBUG
0672     if (!edit) {
0673         qCWarning(KIO_WIDGETS) << "KUrlRequester's lineedit is not a KLineEdit!??\n";
0674     }
0675 #endif
0676 
0677     d->editor.setRepresentationWidget(this);
0678     d->editor.setLineEdit(edit);
0679     return d->editor;
0680 }
0681 
0682 KUrlComboRequester::KUrlComboRequester(QWidget *parent)
0683     : KUrlRequester(new KComboBox(false), parent)
0684     , d(nullptr)
0685 {
0686 }
0687 
0688 #include "kurlrequester.moc"
0689 #include "moc_kurlrequester.cpp"