File indexing completed on 2024-06-16 10:06:22

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 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0080 // regular expression string copied from QPlatformFileDialogHelper
0081 static const QString filterRegExpString = QStringLiteral("^(.*)\\(([a-zA-Z0-9_.,*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$");
0082 #endif
0083 
0084 class Q_DECL_HIDDEN KUrlRequester::KUrlRequesterPrivate
0085 {
0086 public:
0087     explicit KUrlRequesterPrivate(KUrlRequester *parent)
0088         : m_fileDialogModeWasDirAndFile(false)
0089         , m_parent(parent)
0090         , edit(nullptr)
0091         , combo(nullptr)
0092         , fileDialogMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly)
0093         , fileDialogAcceptMode(QFileDialog::AcceptOpen)
0094     {
0095     }
0096 
0097     ~KUrlRequesterPrivate()
0098     {
0099         delete myCompletion;
0100         delete myFileDialog;
0101     }
0102 
0103     void init();
0104 
0105     void setText(const QString &text)
0106     {
0107         if (combo) {
0108             if (combo->isEditable()) {
0109                 combo->setEditText(text);
0110             } else {
0111                 int i = combo->findText(text);
0112                 if (i == -1) {
0113                     combo->addItem(text);
0114                     combo->setCurrentIndex(combo->count() - 1);
0115                 } else {
0116                     combo->setCurrentIndex(i);
0117                 }
0118             }
0119         } else {
0120             edit->setText(text);
0121         }
0122     }
0123 
0124     void connectSignals(KUrlRequester *receiver)
0125     {
0126         if (combo) {
0127             connect(combo, &QComboBox::currentTextChanged, receiver, &KUrlRequester::textChanged);
0128             connect(combo, &QComboBox::editTextChanged, receiver, &KUrlRequester::textEdited);
0129 
0130 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 80)
0131             connect(combo, qOverload<const QString &>(&KComboBox::returnPressed), receiver, qOverload<>(&KUrlRequester::returnPressed));
0132 #endif
0133             connect(combo, qOverload<const QString &>(&KComboBox::returnPressed), receiver, qOverload<const QString &>(&KUrlRequester::returnPressed));
0134         } else if (edit) {
0135             connect(edit, &QLineEdit::textChanged, receiver, &KUrlRequester::textChanged);
0136             connect(edit, &QLineEdit::textEdited, receiver, &KUrlRequester::textEdited);
0137 
0138 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 80)
0139             connect(edit, qOverload<>(&QLineEdit::returnPressed), receiver, qOverload<>(&KUrlRequester::returnPressed));
0140 #else
0141             connect(edit, qOverload<>(&QLineEdit::returnPressed), receiver, [this]() {
0142                 m_parent->Q_EMIT returnPressed(QString{});
0143             });
0144 #endif
0145             if (auto kline = qobject_cast<KLineEdit *>(edit)) {
0146                 connect(kline, &KLineEdit::returnKeyPressed, receiver, qOverload<const QString &>(&KUrlRequester::returnPressed));
0147             }
0148         }
0149     }
0150 
0151     void setCompletionObject(KCompletion *comp)
0152     {
0153         if (combo) {
0154             combo->setCompletionObject(comp);
0155         } else {
0156             edit->setCompletionObject(comp);
0157         }
0158     }
0159 
0160     void updateCompletionStartDir(const QUrl &newStartDir)
0161     {
0162         myCompletion->setDir(newStartDir);
0163     }
0164 
0165     QString text() const
0166     {
0167         return combo ? combo->currentText() : edit->text();
0168     }
0169 
0170     /**
0171      * replaces ~user or $FOO, if necessary
0172      * if text() is a relative path, make it absolute using startDir()
0173      */
0174     QUrl url() const
0175     {
0176         const QString txt = text();
0177         KUrlCompletion *comp;
0178         if (combo) {
0179             comp = qobject_cast<KUrlCompletion *>(combo->completionObject());
0180         } else {
0181             comp = qobject_cast<KUrlCompletion *>(edit->completionObject());
0182         }
0183 
0184         QString enteredPath;
0185         if (comp) {
0186             enteredPath = comp->replacedPath(txt);
0187         } else {
0188             enteredPath = txt;
0189         }
0190 
0191         if (Utils::isAbsoluteLocalPath(enteredPath)) {
0192             return QUrl::fromLocalFile(enteredPath);
0193         }
0194 
0195         const QUrl enteredUrl = QUrl(enteredPath); // absolute or relative
0196         if (enteredUrl.isRelative() && !txt.isEmpty()) {
0197             QUrl finalUrl(m_startDir);
0198             finalUrl.setPath(Utils::concatPaths(finalUrl.path(), enteredPath));
0199             return finalUrl;
0200         } else {
0201             return enteredUrl;
0202         }
0203     }
0204 
0205     static void applyFileMode(QFileDialog *dlg, KFile::Modes m, QFileDialog::AcceptMode acceptMode)
0206     {
0207         QFileDialog::FileMode fileMode;
0208         bool dirsOnly = false;
0209         if (m & KFile::Directory) {
0210             fileMode = QFileDialog::Directory;
0211             if ((m & KFile::File) == 0 && (m & KFile::Files) == 0) {
0212                 dirsOnly = true;
0213             }
0214         } else if (m & KFile::Files && m & KFile::ExistingOnly) {
0215             fileMode = QFileDialog::ExistingFiles;
0216         } else if (m & KFile::File && m & KFile::ExistingOnly) {
0217             fileMode = QFileDialog::ExistingFile;
0218         } else {
0219             fileMode = QFileDialog::AnyFile;
0220         }
0221 
0222         dlg->setFileMode(fileMode);
0223         dlg->setAcceptMode(acceptMode);
0224         dlg->setOption(QFileDialog::ShowDirsOnly, dirsOnly);
0225     }
0226 
0227 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0228     // Converts from "*.foo *.bar|Comment" to "Comment (*.foo *.bar)"
0229     QStringList kToQFilters(const QString &filters) const
0230     {
0231         QStringList qFilters = filters.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
0232 
0233         for (QString &qFilter : qFilters) {
0234             int sep = qFilter.indexOf(QLatin1Char('|'));
0235             if (sep != -1) {
0236                 const QStringView fView(qFilter);
0237                 const auto globs = fView.left(sep).trimmed();
0238                 const auto desc = fView.mid(sep + 1).trimmed();
0239                 qFilter = desc + QLatin1String(" (") + globs + QLatin1Char(')');
0240             }
0241         }
0242 
0243         return qFilters;
0244     }
0245 
0246     // Converts from "Comment (*.foo *.bar)" to "*.foo *.bar|Comment"
0247     static QString qToKFilter(const QStringList &filters)
0248     {
0249         const QRegularExpression regexp(filterRegExpString);
0250         QStringList result;
0251         for (const QString &filter : filters) {
0252             QRegularExpressionMatch match;
0253             filter.indexOf(regexp, 0, &match);
0254             if (match.hasMatch()) {
0255                 result.append(match.capturedView(2).trimmed() + QLatin1Char('|') + match.capturedView(1).trimmed());
0256             } else {
0257                 result.append(filter);
0258             }
0259         }
0260         return result.join(QLatin1Char('\n'));
0261     }
0262 
0263     // Provides work-around for older Plasma Qt Platform Theme integration versions
0264     // only processing filters with explicit names (bug 470893),
0265     // use the filter expressions as name as fallback if no name is given
0266     // TODO: find a way to test if the current theme is a broken Plasma one, otherwise skip
0267     static QStringList ensureNamedFilter(const QStringList &filters)
0268     {
0269         QStringList namedFilters(filters);
0270         const QRegularExpression regexp(filterRegExpString);
0271         for (QString &filter : namedFilters) {
0272             QRegularExpressionMatch match;
0273             filter.indexOf(regexp, 0, &match);
0274             if (!match.hasMatch()) {
0275                 filter = filter + QLatin1String(" (") + filter + QLatin1Char(')');
0276             }
0277         }
0278         return namedFilters;
0279     }
0280 #endif
0281 
0282     QUrl getDirFromFileDialog(const QUrl &openUrl) const
0283     {
0284         return QFileDialog::getExistingDirectoryUrl(m_parent, QString(), openUrl, QFileDialog::ShowDirsOnly);
0285     }
0286 
0287     void createFileDialog()
0288     {
0289         // Creates the fileDialog if it doesn't exist yet
0290         QFileDialog *dlg = m_parent->fileDialog();
0291 
0292         if (!url().isEmpty() && !url().isRelative()) {
0293             QUrl u(url());
0294             // If we won't be able to list it (e.g. http), then don't try :)
0295             if (KProtocolManager::supportsListing(u)) {
0296                 dlg->selectUrl(u);
0297             }
0298         } else {
0299             dlg->setDirectoryUrl(m_startDir);
0300         }
0301 
0302         dlg->setAcceptMode(fileDialogAcceptMode);
0303 
0304         // Update the file dialog window modality
0305         if (dlg->windowModality() != fileDialogModality) {
0306             dlg->setWindowModality(fileDialogModality);
0307         }
0308 
0309         if (fileDialogModality == Qt::NonModal) {
0310             dlg->show();
0311         } else {
0312             dlg->exec();
0313         }
0314     }
0315 
0316     // slots
0317     void slotUpdateUrl();
0318     void slotOpenDialog();
0319     void slotFileDialogAccepted();
0320 
0321     QUrl m_startDir;
0322     bool m_startDirCustomized;
0323     bool m_fileDialogModeWasDirAndFile;
0324     KUrlRequester *const m_parent; // TODO: rename to 'q'
0325     KLineEdit *edit;
0326     KComboBox *combo;
0327     KFile::Modes fileDialogMode;
0328     QFileDialog::AcceptMode fileDialogAcceptMode;
0329     QStringList nameFilters;
0330     QStringList mimeTypeFilters;
0331     KEditListWidget::CustomEditor editor;
0332     KUrlDragPushButton *myButton;
0333     QFileDialog *myFileDialog;
0334     KUrlCompletion *myCompletion;
0335     Qt::WindowModality fileDialogModality;
0336 };
0337 
0338 KUrlRequester::KUrlRequester(QWidget *editWidget, QWidget *parent)
0339     : QWidget(parent)
0340     , d(new KUrlRequesterPrivate(this))
0341 {
0342     // must have this as parent
0343     editWidget->setParent(this);
0344     d->combo = qobject_cast<KComboBox *>(editWidget);
0345     d->edit = qobject_cast<KLineEdit *>(editWidget);
0346     if (d->edit) {
0347         d->edit->setClearButtonEnabled(true);
0348     }
0349 
0350     d->init();
0351 }
0352 
0353 KUrlRequester::KUrlRequester(QWidget *parent)
0354     : QWidget(parent)
0355     , d(new KUrlRequesterPrivate(this))
0356 {
0357     d->init();
0358 }
0359 
0360 KUrlRequester::KUrlRequester(const QUrl &url, QWidget *parent)
0361     : QWidget(parent)
0362     , d(new KUrlRequesterPrivate(this))
0363 {
0364     d->init();
0365     setUrl(url);
0366 }
0367 
0368 KUrlRequester::~KUrlRequester()
0369 {
0370     QWidget *widget = d->combo ? static_cast<QWidget *>(d->combo) : static_cast<QWidget *>(d->edit);
0371     widget->removeEventFilter(this);
0372 }
0373 
0374 void KUrlRequester::KUrlRequesterPrivate::init()
0375 {
0376     myFileDialog = nullptr;
0377     fileDialogModality = Qt::ApplicationModal;
0378 
0379     if (!combo && !edit) {
0380         edit = new KLineEdit(m_parent);
0381         edit->setClearButtonEnabled(true);
0382     }
0383 
0384     QWidget *widget = combo ? static_cast<QWidget *>(combo) : static_cast<QWidget *>(edit);
0385 
0386     QHBoxLayout *topLayout = new QHBoxLayout(m_parent);
0387     topLayout->setContentsMargins(0, 0, 0, 0);
0388     topLayout->setSpacing(-1); // use default spacing
0389     topLayout->addWidget(widget);
0390 
0391     myButton = new KUrlDragPushButton(m_parent);
0392     myButton->setIcon(QIcon::fromTheme(QStringLiteral("document-open")));
0393     int buttonSize = myButton->sizeHint().expandedTo(widget->sizeHint()).height();
0394     myButton->setFixedSize(buttonSize, buttonSize);
0395     myButton->setToolTip(i18n("Open file dialog"));
0396 
0397     connect(myButton, &KUrlDragPushButton::pressed, m_parent, [this]() {
0398         slotUpdateUrl();
0399     });
0400 
0401     widget->installEventFilter(m_parent);
0402     m_parent->setFocusProxy(widget);
0403     m_parent->setFocusPolicy(Qt::StrongFocus);
0404     topLayout->addWidget(myButton);
0405 
0406     connectSignals(m_parent);
0407     connect(myButton, &KUrlDragPushButton::clicked, m_parent, [this]() {
0408         slotOpenDialog();
0409     });
0410 
0411     m_startDir = QUrl::fromLocalFile(QDir::currentPath());
0412     m_startDirCustomized = false;
0413 
0414     myCompletion = new KUrlCompletion();
0415     updateCompletionStartDir(m_startDir);
0416 
0417     setCompletionObject(myCompletion);
0418 
0419     QAction *openAction = new QAction(m_parent);
0420     openAction->setShortcut(QKeySequence::Open);
0421     m_parent->connect(openAction, &QAction::triggered, m_parent, [this]() {
0422         slotOpenDialog();
0423     });
0424 }
0425 
0426 void KUrlRequester::setUrl(const QUrl &url)
0427 {
0428     d->setText(url.toDisplayString(QUrl::PreferLocalFile));
0429 }
0430 
0431 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(4, 3)
0432 void KUrlRequester::setPath(const QString &path)
0433 {
0434     d->setText(path);
0435 }
0436 #endif
0437 
0438 void KUrlRequester::setText(const QString &text)
0439 {
0440     d->setText(text);
0441 }
0442 
0443 void KUrlRequester::setStartDir(const QUrl &startDir)
0444 {
0445     d->m_startDir = startDir;
0446     d->m_startDirCustomized = true;
0447     d->updateCompletionStartDir(startDir);
0448 }
0449 
0450 void KUrlRequester::changeEvent(QEvent *e)
0451 {
0452     if (e->type() == QEvent::WindowTitleChange) {
0453         if (d->myFileDialog) {
0454             d->myFileDialog->setWindowTitle(windowTitle());
0455         }
0456     }
0457     QWidget::changeEvent(e);
0458 }
0459 
0460 QUrl KUrlRequester::url() const
0461 {
0462     return d->url();
0463 }
0464 
0465 QUrl KUrlRequester::startDir() const
0466 {
0467     return d->m_startDir;
0468 }
0469 
0470 QString KUrlRequester::text() const
0471 {
0472     return d->text();
0473 }
0474 
0475 void KUrlRequester::KUrlRequesterPrivate::slotOpenDialog()
0476 {
0477     if (myFileDialog) {
0478         if (myFileDialog->isVisible()) {
0479             // The file dialog is already being shown, raise it and exit
0480             myFileDialog->raise();
0481             myFileDialog->activateWindow();
0482             return;
0483         }
0484     }
0485 
0486     if (!m_fileDialogModeWasDirAndFile
0487         && (((fileDialogMode & KFile::Directory) && !(fileDialogMode & KFile::File)) ||
0488             /* catch possible fileDialog()->setMode( KFile::Directory ) changes */
0489             (myFileDialog && (myFileDialog->fileMode() == QFileDialog::Directory && myFileDialog->testOption(QFileDialog::ShowDirsOnly))))) {
0490         const QUrl openUrl = (!m_parent->url().isEmpty() && !m_parent->url().isRelative()) ? m_parent->url() : m_startDir;
0491 
0492         /* FIXME We need a new abstract interface for using KDirSelectDialog in a non-modal way */
0493 
0494         QUrl newUrl;
0495         if (fileDialogMode & KFile::LocalOnly) {
0496             newUrl = QFileDialog::getExistingDirectoryUrl(m_parent, QString(), openUrl, QFileDialog::ShowDirsOnly, QStringList() << QStringLiteral("file"));
0497         } else {
0498             newUrl = getDirFromFileDialog(openUrl);
0499         }
0500 
0501         if (newUrl.isValid()) {
0502             m_parent->setUrl(newUrl);
0503             Q_EMIT m_parent->urlSelected(url());
0504         }
0505     } else {
0506         Q_EMIT m_parent->openFileDialog(m_parent);
0507 
0508         if (((fileDialogMode & KFile::Directory) && (fileDialogMode & KFile::File)) || m_fileDialogModeWasDirAndFile) {
0509             QMenu *dirOrFileMenu = new QMenu();
0510             QAction *fileAction = new QAction(QIcon::fromTheme(QStringLiteral("document-new")), i18n("File"));
0511             QAction *dirAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Directory"));
0512             dirOrFileMenu->addAction(fileAction);
0513             dirOrFileMenu->addAction(dirAction);
0514 
0515             connect(fileAction, &QAction::triggered, [this]() {
0516                 fileDialogMode = KFile::File;
0517                 applyFileMode(m_parent->fileDialog(), fileDialogMode, fileDialogAcceptMode);
0518                 m_fileDialogModeWasDirAndFile = true;
0519                 createFileDialog();
0520             });
0521 
0522             connect(dirAction, &QAction::triggered, [this]() {
0523                 fileDialogMode = KFile::Directory;
0524                 applyFileMode(m_parent->fileDialog(), fileDialogMode, fileDialogAcceptMode);
0525                 m_fileDialogModeWasDirAndFile = true;
0526                 createFileDialog();
0527             });
0528 
0529             dirOrFileMenu->exec(m_parent->mapToGlobal(QPoint(m_parent->width(), m_parent->height())));
0530 
0531             return;
0532         }
0533 
0534         createFileDialog();
0535     }
0536 }
0537 
0538 void KUrlRequester::KUrlRequesterPrivate::slotFileDialogAccepted()
0539 {
0540     if (!myFileDialog) {
0541         return;
0542     }
0543 
0544     const QUrl newUrl = myFileDialog->selectedUrls().constFirst();
0545     if (newUrl.isValid()) {
0546         m_parent->setUrl(newUrl);
0547         Q_EMIT m_parent->urlSelected(url());
0548         // remember url as defaultStartDir and update startdir for autocompletion
0549         if (newUrl.isLocalFile() && !m_startDirCustomized) {
0550             m_startDir = newUrl.adjusted(QUrl::RemoveFilename);
0551             updateCompletionStartDir(m_startDir);
0552         }
0553     }
0554 }
0555 
0556 void KUrlRequester::setMode(KFile::Modes mode)
0557 {
0558     Q_ASSERT((mode & KFile::Files) == 0);
0559     d->fileDialogMode = mode;
0560     if ((mode & KFile::Directory) && !(mode & KFile::File)) {
0561         d->myCompletion->setMode(KUrlCompletion::DirCompletion);
0562     }
0563 
0564     if (d->myFileDialog) {
0565         d->applyFileMode(d->myFileDialog, mode, d->fileDialogAcceptMode);
0566     }
0567 }
0568 
0569 KFile::Modes KUrlRequester::mode() const
0570 {
0571     return d->fileDialogMode;
0572 }
0573 
0574 void KUrlRequester::setAcceptMode(QFileDialog::AcceptMode mode)
0575 {
0576     d->fileDialogAcceptMode = mode;
0577 
0578     if (d->myFileDialog) {
0579         d->applyFileMode(d->myFileDialog, d->fileDialogMode, mode);
0580     }
0581 }
0582 
0583 QFileDialog::AcceptMode KUrlRequester::acceptMode() const
0584 {
0585     return d->fileDialogAcceptMode;
0586 }
0587 
0588 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0589 void KUrlRequester::setFilter(const QString &filter)
0590 {
0591     d->nameFilters = d->kToQFilters(filter);
0592 
0593     if (d->myFileDialog) {
0594         d->myFileDialog->setNameFilters(d->ensureNamedFilter(d->nameFilters));
0595     }
0596 }
0597 #endif
0598 
0599 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0600 QString KUrlRequester::filter() const
0601 {
0602     return d->qToKFilter(d->nameFilters);
0603 }
0604 #endif
0605 
0606 QStringList KUrlRequester::nameFilters() const
0607 {
0608     return d->nameFilters;
0609 }
0610 
0611 void KUrlRequester::setNameFilters(const QStringList &filters)
0612 {
0613     d->nameFilters = filters;
0614 
0615     if (d->myFileDialog) {
0616 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0617         d->myFileDialog->setNameFilters(d->ensureNamedFilter(d->nameFilters));
0618 #else
0619         d->myFileDialog->setNameFilters(d->nameFilters);
0620 #endif
0621     }
0622 }
0623 
0624 void KUrlRequester::setNameFilter(const QString &filter)
0625 {
0626     if (filter.isEmpty()) {
0627         setNameFilters(QStringList());
0628         return;
0629     }
0630 
0631     // by default use ";;" as separator
0632     // if not present, support alternatively "\n" (matching QFileDialog behaviour)
0633     // if also not present split() will simply return the string passed in
0634     QString separator = QStringLiteral(";;");
0635     if (!filter.contains(separator)) {
0636         separator = QStringLiteral("\n");
0637     }
0638     setNameFilters(filter.split(separator));
0639 }
0640 
0641 void KUrlRequester::setMimeTypeFilters(const QStringList &mimeTypes)
0642 {
0643     d->mimeTypeFilters = mimeTypes;
0644 
0645     if (d->myFileDialog) {
0646         d->myFileDialog->setMimeTypeFilters(d->mimeTypeFilters);
0647     }
0648     d->myCompletion->setMimeTypeFilters(d->mimeTypeFilters);
0649 }
0650 
0651 QStringList KUrlRequester::mimeTypeFilters() const
0652 {
0653     return d->mimeTypeFilters;
0654 }
0655 
0656 QFileDialog *KUrlRequester::fileDialog() const
0657 {
0658     if (d->myFileDialog
0659         && ((d->myFileDialog->fileMode() == QFileDialog::Directory && !(d->fileDialogMode & KFile::Directory))
0660             || (d->myFileDialog->fileMode() != QFileDialog::Directory && (d->fileDialogMode & KFile::Directory)))) {
0661         delete d->myFileDialog;
0662         d->myFileDialog = nullptr;
0663     }
0664 
0665     if (!d->myFileDialog) {
0666         d->myFileDialog = new QFileDialog(window(), windowTitle());
0667         if (!d->mimeTypeFilters.isEmpty()) {
0668             d->myFileDialog->setMimeTypeFilters(d->mimeTypeFilters);
0669         } else {
0670 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 108)
0671             d->myFileDialog->setNameFilters(d->ensureNamedFilter(d->nameFilters));
0672 #else
0673             d->myFileDialog->setNameFilters(d->nameFilters);
0674 #endif
0675         }
0676 
0677         d->applyFileMode(d->myFileDialog, d->fileDialogMode, d->fileDialogAcceptMode);
0678 
0679         d->myFileDialog->setWindowModality(d->fileDialogModality);
0680         connect(d->myFileDialog, &QFileDialog::accepted, this, [this]() {
0681             d->slotFileDialogAccepted();
0682         });
0683     }
0684 
0685     return d->myFileDialog;
0686 }
0687 
0688 void KUrlRequester::clear()
0689 {
0690     d->setText(QString());
0691 }
0692 
0693 KLineEdit *KUrlRequester::lineEdit() const
0694 {
0695     return d->edit;
0696 }
0697 
0698 KComboBox *KUrlRequester::comboBox() const
0699 {
0700     return d->combo;
0701 }
0702 
0703 void KUrlRequester::KUrlRequesterPrivate::slotUpdateUrl()
0704 {
0705     const QUrl visibleUrl = url();
0706     QUrl u = visibleUrl;
0707     if (visibleUrl.isRelative()) {
0708         u = QUrl::fromLocalFile(QDir::currentPath() + QLatin1Char('/')).resolved(visibleUrl);
0709     }
0710     myButton->setURL(u);
0711 }
0712 
0713 bool KUrlRequester::eventFilter(QObject *obj, QEvent *ev)
0714 {
0715     if ((d->edit == obj) || (d->combo == obj)) {
0716         if ((ev->type() == QEvent::FocusIn) || (ev->type() == QEvent::FocusOut))
0717         // Forward focusin/focusout events to the urlrequester; needed by file form element in khtml
0718         {
0719             QApplication::sendEvent(this, ev);
0720         }
0721     }
0722     return QWidget::eventFilter(obj, ev);
0723 }
0724 
0725 QPushButton *KUrlRequester::button() const
0726 {
0727     return d->myButton;
0728 }
0729 
0730 KUrlCompletion *KUrlRequester::completionObject() const
0731 {
0732     return d->myCompletion;
0733 }
0734 
0735 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 0)
0736 void KUrlRequester::setClickMessage(const QString &msg)
0737 {
0738     setPlaceholderText(msg);
0739 }
0740 #endif
0741 
0742 void KUrlRequester::setPlaceholderText(const QString &msg)
0743 {
0744     if (d->edit) {
0745         d->edit->setPlaceholderText(msg);
0746     }
0747 }
0748 
0749 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 0)
0750 QString KUrlRequester::clickMessage() const
0751 {
0752     return placeholderText();
0753 }
0754 #endif
0755 
0756 QString KUrlRequester::placeholderText() const
0757 {
0758     if (d->edit) {
0759         return d->edit->placeholderText();
0760     } else {
0761         return QString();
0762     }
0763 }
0764 
0765 Qt::WindowModality KUrlRequester::fileDialogModality() const
0766 {
0767     return d->fileDialogModality;
0768 }
0769 
0770 void KUrlRequester::setFileDialogModality(Qt::WindowModality modality)
0771 {
0772     d->fileDialogModality = modality;
0773 }
0774 
0775 const KEditListWidget::CustomEditor &KUrlRequester::customEditor()
0776 {
0777     setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
0778 
0779     KLineEdit *edit = d->edit;
0780     if (!edit && d->combo) {
0781         edit = qobject_cast<KLineEdit *>(d->combo->lineEdit());
0782     }
0783 
0784 #ifndef NDEBUG
0785     if (!edit) {
0786         qCWarning(KIO_WIDGETS) << "KUrlRequester's lineedit is not a KLineEdit!??\n";
0787     }
0788 #endif
0789 
0790     d->editor.setRepresentationWidget(this);
0791     d->editor.setLineEdit(edit);
0792     return d->editor;
0793 }
0794 
0795 KUrlComboRequester::KUrlComboRequester(QWidget *parent)
0796     : KUrlRequester(new KComboBox(false), parent)
0797     , d(nullptr)
0798 {
0799 }
0800 
0801 #include "kurlrequester.moc"
0802 #include "moc_kurlrequester.cpp"