File indexing completed on 2024-12-08 03:40:50
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"