diff --git a/src/browseropenorsavequestion.cpp b/src/browseropenorsavequestion.cpp index 8519c6a..7e9c48e 100644 --- a/src/browseropenorsavequestion.cpp +++ b/src/browseropenorsavequestion.cpp @@ -1,365 +1,365 @@ /* Copyright (c) 2009, 2010 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "browseropenorsavequestion.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KParts; Q_DECLARE_METATYPE(KService::Ptr) class KParts::BrowserOpenOrSaveQuestionPrivate : public QDialog { Q_OBJECT public: enum { Save = QDialog::Accepted, OpenDefault = Save + 1, OpenWith = OpenDefault + 1, Cancel = QDialog::Rejected }; BrowserOpenOrSaveQuestionPrivate(QWidget *parent, const QUrl &url, const QString &mimeType) : QDialog(parent), url(url), mimeType(mimeType), features(BrowserOpenOrSaveQuestion::BasicFeatures) { const int spacingHint = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); // Use askSave or askEmbedOrSave from filetypesrc dontAskConfig = KSharedConfig::openConfig(QStringLiteral("filetypesrc"), KConfig::NoGlobals); setWindowTitle(url.host()); setObjectName(QStringLiteral("questionYesNoCancel")); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(spacingHint * 2); // provide extra spacing QHBoxLayout *hLayout = new QHBoxLayout(); mainLayout->addLayout(hLayout, 5); QLabel *iconLabel = new QLabel(this); QStyleOption option; option.initFrom(this); QIcon icon = QIcon::fromTheme(QStringLiteral("dialog-information")); iconLabel->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this))); hLayout->addWidget(iconLabel, 0, Qt::AlignCenter); hLayout->addSpacing(spacingHint); QVBoxLayout *textVLayout = new QVBoxLayout; questionLabel = new KSqueezedTextLabel(this); textVLayout->addWidget(questionLabel); fileNameLabel = new QLabel(this); fileNameLabel->hide(); textVLayout->addWidget(fileNameLabel); QMimeDatabase db; mime = db.mimeTypeForName(mimeType); QString mimeDescription(mimeType); if (mime.isValid()) { // Always prefer the mime-type comment over the raw type for display mimeDescription = (mime.comment().isEmpty() ? mime.name() : mime.comment()); } QLabel *mimeTypeLabel = new QLabel(this); mimeTypeLabel->setText(i18nc("@label Type of file", "Type: %1", mimeDescription)); mimeTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); textVLayout->addWidget(mimeTypeLabel); hLayout->addLayout(textVLayout, 5); mainLayout->addStretch(15); dontAskAgainCheckBox = new QCheckBox(this); dontAskAgainCheckBox->setText(i18nc("@label:checkbox", "Remember action for files of this type")); mainLayout->addWidget(dontAskAgainCheckBox); buttonBox = new QDialogButtonBox(this); saveButton = buttonBox->addButton(QDialogButtonBox::Yes); saveButton->setObjectName(QStringLiteral("saveButton")); KGuiItem::assign(saveButton, KStandardGuiItem::saveAs()); saveButton->setDefault(true); openDefaultButton = new QPushButton; openDefaultButton->setObjectName(QStringLiteral("openDefaultButton")); buttonBox->addButton(openDefaultButton, QDialogButtonBox::ActionRole); openWithButton = new QPushButton; openWithButton->setObjectName(QStringLiteral("openWithButton")); buttonBox->addButton(openWithButton, QDialogButtonBox::ActionRole); QPushButton *cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel); cancelButton->setObjectName(QStringLiteral("cancelButton")); connect(saveButton, &QPushButton::clicked, this, &BrowserOpenOrSaveQuestionPrivate::slotYesClicked); connect(openDefaultButton, &QPushButton::clicked, this, &BrowserOpenOrSaveQuestionPrivate::slotOpenDefaultClicked); connect(openWithButton, &QPushButton::clicked, this, &BrowserOpenOrSaveQuestionPrivate::slotOpenWithClicked); connect(buttonBox, &QDialogButtonBox::rejected, this, &BrowserOpenOrSaveQuestionPrivate::reject); mainLayout->addWidget(buttonBox); } bool autoEmbedMimeType(int flags); int executeDialog(const QString &dontShowAgainName) { KConfigGroup cg(dontAskConfig, "Notification Messages"); // group name comes from KMessageBox const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower(); if (dontAsk == QLatin1String("yes") || dontAsk == QLatin1String("true")) { return Save; } else if (dontAsk == QLatin1String("no") || dontAsk == QLatin1String("false")) { return OpenDefault; } const int result = exec(); if (dontAskAgainCheckBox->isChecked()) { cg.writeEntry(dontShowAgainName, result == BrowserOpenOrSaveQuestion::Save); cg.sync(); } return result; } void showService(KService::Ptr selectedService) { KGuiItem openItem(i18nc("@label:button", "&Open with %1", selectedService->name()), selectedService->icon()); KGuiItem::assign(openWithButton, openItem); } QUrl url; QString mimeType; QMimeType mime; KService::Ptr selectedService; KSqueezedTextLabel *questionLabel; BrowserOpenOrSaveQuestion::Features features; QLabel *fileNameLabel; QDialogButtonBox *buttonBox; QPushButton *saveButton; QPushButton *openDefaultButton; QPushButton *openWithButton; private: QCheckBox *dontAskAgainCheckBox; KSharedConfig::Ptr dontAskConfig; public Q_SLOTS: void reject() override { selectedService = nullptr; QDialog::reject(); } void slotYesClicked() { selectedService = nullptr; done(Save); } void slotOpenDefaultClicked() { done(OpenDefault); } void slotOpenWithClicked() { if (!openWithButton->menu()) { selectedService = nullptr; done(OpenWith); } } void slotAppSelected(QAction *action) { selectedService = action->data().value(); //showService(selectedService); done(OpenDefault); } }; BrowserOpenOrSaveQuestion::BrowserOpenOrSaveQuestion(QWidget *parent, const QUrl &url, const QString &mimeType) : d(new BrowserOpenOrSaveQuestionPrivate(parent, url, mimeType)) { } BrowserOpenOrSaveQuestion::~BrowserOpenOrSaveQuestion() { delete d; } static QAction *createAppAction(const KService::Ptr &service, QObject *parent) { QString actionName(service->name().replace(QLatin1Char('&'), QLatin1String("&&"))); actionName = i18nc("@action:inmenu", "Open &with %1", actionName); QAction *act = new QAction(parent); act->setIcon(QIcon::fromTheme(service->icon())); act->setText(actionName); act->setData(QVariant::fromValue(service)); return act; } BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askOpenOrSave() { d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.toDisplayString(QUrl::PreferLocalFile))); d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); d->openWithButton->hide(); KGuiItem openWithDialogItem(i18nc("@label:button", "&Open with..."), QStringLiteral("document-open")); // I thought about using KFileItemActions, but we don't want a submenu, nor the slots.... // and we want no menu at all if there's only one offer. // TODO: we probably need a setTraderConstraint(), to exclude the current application? const KService::List apps = KFileItemActions::associatedApplications(QStringList() << d->mimeType, QString() /* TODO trader constraint */); if (apps.isEmpty()) { KGuiItem::assign(d->openDefaultButton, openWithDialogItem); } else { KService::Ptr offer = apps.first(); KGuiItem openItem(i18nc("@label:button", "&Open with %1", offer->name()), offer->icon()); KGuiItem::assign(d->openDefaultButton, openItem); if (d->features & ServiceSelection) { // OpenDefault shall use this service d->selectedService = apps.first(); d->openWithButton->show(); QMenu *menu = new QMenu(d); if (apps.count() > 1) { // Provide an additional button with a menu of associated apps KGuiItem openWithItem(i18nc("@label:button", "&Open with"), QStringLiteral("document-open")); KGuiItem::assign(d->openWithButton, openWithItem); d->openWithButton->setMenu(menu); QObject::connect(menu, &QMenu::triggered, d, &BrowserOpenOrSaveQuestionPrivate::slotAppSelected); for (const auto &app : apps) { QAction *act = createAppAction(app, d); menu->addAction(act); } QAction *openWithDialogAction = new QAction(d); openWithDialogAction->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); openWithDialogAction->setText(openWithDialogItem.text()); menu->addAction(openWithDialogAction); } else { // Only one associated app, already offered by the other menu -> add "Open With..." button KGuiItem::assign(d->openWithButton, openWithDialogItem); } } else { // qDebug() << "Not using new feature ServiceSelection; port the caller to BrowserOpenOrSaveQuestion::setFeature(ServiceSelection)"; } } // KEEP IN SYNC with kdebase/runtime/keditfiletype/filetypedetails.cpp!!! const QString dontAskAgain = QLatin1String("askSave") + d->mimeType; const int choice = d->executeDialog(dontAskAgain); return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Open); } KService::Ptr BrowserOpenOrSaveQuestion::selectedService() const { return d->selectedService; } bool BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType(int flags) { // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC // NOTE: Keep this function in sync with // kdebase/runtime/keditfiletype/filetypedetails.cpp // FileTypeDetails::updateAskSave() // Don't ask for: // - html (even new tabs would ask, due to about:blank!) // - dirs obviously (though not common over HTTP :), // - images (reasoning: no need to save, most of the time, because fast to see) // e.g. postscript is different, because takes longer to read, so // it's more likely that the user might want to save it. // - multipart/* ("server push", see kmultipart) // KEEP IN SYNC!!! - if (flags != static_cast(BrowserRun::AttachmentDisposition) && mime.isValid() && ( + if (flags != static_cast(BrowserOpenOrSaveQuestion::AttachmentDisposition) && mime.isValid() && ( mime.inherits(QStringLiteral("text/html")) || mime.inherits(QStringLiteral("application/xml")) || mime.inherits(QStringLiteral("inode/directory")) || mimeType.startsWith(QLatin1String("image")) || mime.inherits(QStringLiteral("multipart/x-mixed-replace")) || mime.inherits(QStringLiteral("multipart/replace")))) { return true; } return false; } BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askEmbedOrSave(int flags) { if (d->autoEmbedMimeType(flags)) { return Embed; } // don't use KStandardGuiItem::open() here which has trailing ellipsis! KGuiItem::assign(d->openDefaultButton, KGuiItem(i18nc("@label:button", "&Open"), QStringLiteral("document-open"))); d->openWithButton->hide(); d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.toDisplayString(QUrl::PreferLocalFile))); d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); const QString dontAskAgain = QLatin1String("askEmbedOrSave") + d->mimeType; // KEEP IN SYNC!!! // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC const int choice = d->executeDialog(dontAskAgain); return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Embed); } void BrowserOpenOrSaveQuestion::setFeatures(Features features) { d->features = features; } void BrowserOpenOrSaveQuestion::setSuggestedFileName(const QString &suggestedFileName) { if (suggestedFileName.isEmpty()) { return; } d->fileNameLabel->setText(i18nc("@label File name", "Name: %1", suggestedFileName)); d->fileNameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); d->fileNameLabel->setWhatsThis(i18nc("@info:whatsthis", "This is the file name suggested by the server")); d->fileNameLabel->show(); } #include "browseropenorsavequestion.moc" diff --git a/src/browseropenorsavequestion.h b/src/browseropenorsavequestion.h index 11f283d..52907a5 100644 --- a/src/browseropenorsavequestion.h +++ b/src/browseropenorsavequestion.h @@ -1,113 +1,120 @@ /* Copyright (c) 2009 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License or ( at your option ) version 3 or, at the discretion of KDE e.V. ( which shall act as a proxy as in section 14 of the GPLv3 ), any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef BROWSEROPENORSAVEQUESTION_H #define BROWSEROPENORSAVEQUESTION_H #include #include #include namespace KParts { class BrowserOpenOrSaveQuestionPrivate; /** * This class shows the dialog that asks the user whether to * save a url or open a url in another application. * * It also has the variant which asks "save or embed" (e.g. into konqueror). * * @since 4.4 */ class KPARTS_EXPORT BrowserOpenOrSaveQuestion { public: /** * Constructor, for all kinds of dialogs shown in this class. * @param url the URL in question * @param mimeType the mimetype of the URL */ BrowserOpenOrSaveQuestion(QWidget *parent, const QUrl &url, const QString &mimeType); ~BrowserOpenOrSaveQuestion(); /** * Sets the suggested filename, shown in the dialog. * @param suggestedFileName optional file name suggested by the server (HTTP Content-Disposition) */ void setSuggestedFileName(const QString &suggestedFileName); /** * Set of features that should be enabled in this dialog. * This allows to add features before making all applications ready for those features * (e.g. applications need to read selectedService() otherwise the dialog should not * show the service selection button) */ enum Feature { BasicFeatures = 0, /**< Only the basic save, open, embed, cancel button */ ServiceSelection = 1 /**< Shows "Open With..." with the associated applications for the mimetype */ }; Q_DECLARE_FLAGS(Features, Feature) /** * Enables the given features in the dialog */ void setFeatures(Features features); enum Result { Save, Open, Embed, Cancel }; /** * Ask the user whether to save or open a url in another application. * @return Save, Open or Cancel. */ Result askOpenOrSave(); + /** + * @since 5.64 + */ + enum AskEmbedOrSaveFlags { + InlineDisposition = 0, + AttachmentDisposition = 1, + }; + /** * Ask the user whether to save or open a url in another application. - * @param flags set to BrowserRun::AttachmentDisposition if suggested by the server + * @param flags set to AttachmentDisposition if suggested by the server * This is used because by default text/html files are opened embedded in browsers, not saved. * But if the server said "attachment", it means the user is download a file for saving it. * @return Save, Embed or Cancel. */ Result askEmbedOrSave(int flags = 0); - // KDE5 TODO: move BrowserRun::AskEmbedOrSaveFlags to this class. // TODO askOpenEmbedOrSave /** * @return the service that was selected during askOpenOrSave, * if it returned Open. * In all other cases (no associated application, Save or Cancel * selected), this returns 0. * * Requires setFeatures(BrowserOpenOrSaveQuestion::ServiceSelection). */ KService::Ptr selectedService() const; private: BrowserOpenOrSaveQuestionPrivate *const d; Q_DISABLE_COPY(BrowserOpenOrSaveQuestion) }; } #endif /* BROWSEROPENORSAVEQUESTION_H */ diff --git a/src/browserrun.h b/src/browserrun.h index 4dd229b..4784b03 100644 --- a/src/browserrun.h +++ b/src/browserrun.h @@ -1,218 +1,221 @@ /* This file is part of the KDE project * * Copyright (C) 2002 David Faure * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef kparts_browserrun_h #define kparts_browserrun_h #include #include #include namespace KParts { /** * This class extends KRun to provide additional functionality for browsers: * - "save or open" dialog boxes * - "save" functionality * - support for HTTP POST (including saving the result to a temp file if * opening a separate application) * - warning before launching executables off the web * - custom error handling (i.e. treating errors as HTML pages) * - generation of SSL metadata depending on the previous URL shown by the part * @author David Faure */ class KPARTS_EXPORT BrowserRun : public KRun { Q_OBJECT public: /** * @param url the URL we're probing * @param args URL args - includes reload, metaData, etc. * @param browserArgs browser-related args - includes data for a HTTP POST, etc. * @param part the part going to open this URL - can be @c nullptr if not created yet * @param window the mainwindow - passed to KIO::Job::setWindow() * @param removeReferrer if true, the "referrer" metadata from @p args isn't passed on * @param trustedSource if false, a warning will be shown before launching an executable. Always pass false for @p trustedSource, except for local directory views. * @param hideErrorDialog if true, no dialog will be shown in case of errors. */ BrowserRun(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs, KParts::ReadOnlyPart *part, QWidget *window, bool removeReferrer, bool trustedSource, bool hideErrorDialog = false); virtual ~BrowserRun(); KParts::OpenUrlArguments &arguments(); KParts::BrowserArguments &browserArguments(); KParts::ReadOnlyPart *part() const; QUrl url() const; bool hideErrorDialog() const; /** * @return Suggested disposition by the server (e.g. HTTP content-disposition) */ QString contentDisposition() const; /** * @return Whether the returned disposition suggests saving or opening inline */ bool serverSuggestsSave() const; #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) enum AskSaveResult { Save, Open, Cancel }; /** * Ask the user whether to save or open a url in another application. * @param url the URL in question * @param offer the application that will be used to open the URL * @param mimeType the mimetype of the URL * @param suggestedFileName optional file name suggested by the server * @return Save, Open or Cancel. * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askOpenOrSave(); * @endcode */ KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") static AskSaveResult askSave(const QUrl &url, KService::Ptr offer, const QString &mimeType, const QString &suggestedFileName = QString()); #endif +#if KPARTS_ENABLE_DEPRECATED_SINCE(5, 64) + /** @deprecated Since 5.64, use BrowserOpenOrSaveQuestion::AskEmbedOrSaveFlags */ enum AskEmbedOrSaveFlags { InlineDisposition = 0, AttachmentDisposition = 1 }; +#endif #if KPARTS_ENABLE_DEPRECATED_SINCE(5, 0) /** * Similar to askSave but for the case where the current application is * able to embed the url itself (instead of passing it to another app). * @param url the URL in question * @param mimeType the mimetype of the URL * @param suggestedFileName optional filename suggested by the server * @param flags set to AttachmentDisposition if suggested by the server * @return Save, Open or Cancel. * @deprecated Since 5.0, use BrowserOpenOrSaveQuestion * @code * BrowserOpenOrSaveQuestion dlg(parent, url, mimeType, suggestedFileName); * const BrowserOpenOrSaveQuestion::Result res = dlg.askEmbedOrSave(flags); * // Important: returns Embed now, not Open! * @endcode */ KPARTS_DEPRECATED_VERSION(5, 0, "Use KParts::BrowserOpenOrSaveQuestion") static AskSaveResult askEmbedOrSave(const QUrl &url, const QString &mimeType, const QString &suggestedFileName = QString(), int flags = 0); #endif // virtual so that KHTML can implement differently (HTML cache) virtual void save(const QUrl &url, const QString &suggestedFileName); // static so that it can be called from other classes static void simpleSave(const QUrl &url, const QString &suggestedFileName, QWidget *window = nullptr); // KDE5: remove /** * If kget integration is enabled, passes the url to kget. * Otherwise, asks the user for a destination url, and calls saveUrlUsingKIO. * @since 4.4 */ static void saveUrl(const QUrl &url, const QString &suggestedFileName, QWidget *window, const KParts::OpenUrlArguments &args); /** * Starts the KIO file copy job to download @p srcUrl into @p destUrl. * @since 4.4 */ static void saveUrlUsingKIO(const QUrl &srcUrl, const QUrl &destUrl, QWidget *window, const QMap &metaData); static bool allowExecution(const QString &mimeType, const QUrl &url); static bool isTextExecutable(const QString &mimeType); /** * KDE webbrowsing kparts support error urls to display errors in-line in the browser component. * This helper method creates the error URL from its parameters. * @param error the KIO error code (or KIO::ERR_SLAVE_DEFINED if not from KIO) * @param errorText the text of the error message * @param initialUrl the URL that we were trying to open (as a string, so that this can * support invalid URLs as well) (changed from QString to QUrl in KF5) * @since 4.6 */ static QUrl makeErrorUrl(int error, const QString &errorText, const QUrl &initialUrl); protected: /** * Reimplemented from KRun */ void scanFile() override; /** * Reimplemented from KRun */ void init() override; /** * Reimplemented from KRun */ void handleError(KJob *job) override; /** * NotHandled means that foundMimeType should call KRun::foundMimeType, * i.e. launch an external app. */ enum NonEmbeddableResult { Handled, NotHandled, Delayed }; /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType); // TODO KDE5: remove, and add =0 to the other overload /** * Helper for foundMimeType: call this if the mimetype couldn't be embedded * @param mimeType the mimetype found for the URL * @param pSelectedService Output variable: pointer to a KService::Ptr, which will be set * to the service selected in the BrowserOpenOrSaveQuestion dialog, if any. * * How to handle this properly: if pSelectedService is non-zero, then the dialog will show * additional "open with" buttons. In your code, you should write: * @code if (selectedService) { KRun::setPreferredService(selectedService->desktopEntryName()); // not necessary since 4.9.3 KRun::foundMimeType(mimeType); } else { // the user requested an open-with dialog KRun::displayOpenWithDialog(url(), m_window, false, suggestedFileName()); setFinished(true); } * @endcode * * @since 4.5 */ NonEmbeddableResult handleNonEmbeddable(const QString &mimeType, KService::Ptr *pSelectedService); protected Q_SLOTS: void slotBrowserScanFinished(KJob *job); void slotBrowserMimetype(KIO::Job *job, const QString &type); void slotCopyToTempFileResult(KJob *job); private: void redirectToError(int error, const QString &errorText); class BrowserRunPrivate; BrowserRunPrivate *const d; }; } #endif