summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainwindow.cpp30
-rw-r--r--src/webpage.cpp244
-rw-r--r--src/webpage.h9
3 files changed, 175 insertions, 108 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 11c00c28..599295f7 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -619,26 +619,28 @@ void MainWindow::openLocation()
void MainWindow::fileSaveAs()
{
- KUrl srcUrl;
WebTab *w = currentTab();
- if (w->page()->isOnRekonqPage())
- {
- QWebElement el = w->page()->mainFrame()->documentElement();
- srcUrl = KUrl( el.findFirst("object").attribute("data") );
- }
- else
+ KUrl srcUrl = w->url();
+
+ // First, try with suggested file name...
+ QString name = w->page()->suggestedFileName();
+
+ // Second, with KUrl fileName...
+ if (name.isEmpty())
{
- srcUrl = w->url();
+ name = srcUrl.fileName();
}
- kDebug() << "URL to save: " << srcUrl;
-
- QString name = srcUrl.fileName();
- if (name.isNull())
+
+ // Last chance...
+ if(name.isEmpty())
{
name = srcUrl.host() + QString(".html");
}
+
const QString destUrl = KFileDialog::getSaveFileName(name, QString(), this);
- if (destUrl.isEmpty()) return;
+ if (destUrl.isEmpty())
+ return;
+
KIO::Job *job = KIO::file_copy(srcUrl, KUrl(destUrl), -1, KIO::Overwrite);
job->addMetaData("MaxCacheSize", "0"); // Don't store in http cache.
job->addMetaData("cache", "cache"); // Use entry from cache if available.
@@ -984,7 +986,6 @@ void MainWindow::openPrevious(Qt::MouseButtons mouseButtons, Qt::KeyboardModifie
if (currentTab()->page()->isOnRekonqPage())
{
item = new QWebHistoryItem(history->currentItem());
- currentTab()->view()->page()->setIsOnRekonqPage(false);
}
else
{
@@ -1018,7 +1019,6 @@ void MainWindow::openNext(Qt::MouseButtons mouseButtons, Qt::KeyboardModifiers k
if (currentTab()->view()->page()->isOnRekonqPage())
{
item = new QWebHistoryItem(history->currentItem());
- currentTab()->view()->page()->setIsOnRekonqPage(false);
}
else
{
diff --git a/src/webpage.cpp b/src/webpage.cpp
index b04c5e89..c7ddfd5b 100644
--- a/src/webpage.cpp
+++ b/src/webpage.cpp
@@ -54,6 +54,9 @@
// KDE Includes
#include <KIO/Job>
#include <KIO/RenameDialog>
+#include <KIO/JobUiDelegate>
+
+#include <KTemporaryFile>
#include <KStandardDirs>
#include <KFileDialog>
#include <KJobUiDelegate>
@@ -66,6 +69,8 @@
#include <kparts/browseropenorsavequestion.h>
+#include <kio/scheduler.h>
+
// Qt Includes
#include <QtCore/QFileInfo>
@@ -99,10 +104,67 @@ static bool domainSchemeMatch(const QUrl& u1, const QUrl& u2)
// NOTE
-// This is heavily based on the one from KdeWebKit and
-// extended to provide the extra functionality we need:
+// These 2 functions have been copied from the KWebPage class to implement a local version of the downloadResponse method.
+// In this way, we can easily provide the extra functionality we need:
// 1. KGet Integration
// 2. Save downloads history
+static void extractSuggestedFileName(const QNetworkReply* reply, QString& fileName)
+{
+ fileName.clear();
+ const KIO::MetaData& metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
+ if (metaData.value(QL1S("content-disposition-type")).compare(QL1S("attachment"), Qt::CaseInsensitive) == 0)
+ fileName = metaData.value(QL1S("content-disposition-filename"));
+
+ if (!fileName.isEmpty())
+ return;
+
+ if (!reply->hasRawHeader("Content-Disposition"))
+ return;
+
+ const QString value (QL1S(reply->rawHeader("Content-Disposition").simplified().constData()));
+ if (value.startsWith(QL1S("attachment"), Qt::CaseInsensitive) || value.startsWith(QL1S("inline"), Qt::CaseInsensitive))
+ {
+ const int length = value.size();
+ int pos = value.indexOf(QL1S("filename"), 0, Qt::CaseInsensitive);
+ if (pos > -1)
+ {
+ pos += 9;
+ while (pos < length && (value.at(pos) == QL1C(' ') || value.at(pos) == QL1C('=') || value.at(pos) == QL1C('"')))
+ pos++;
+
+ int endPos = pos;
+ while (endPos < length && value.at(endPos) != QL1C('"') && value.at(endPos) != QL1C(';'))
+ endPos++;
+
+ if (endPos > pos)
+ fileName = value.mid(pos, (endPos-pos)).trimmed();
+ }
+ }
+}
+
+
+static void extractMimeType(const QNetworkReply* reply, QString& mimeType)
+{
+ mimeType.clear();
+ const KIO::MetaData& metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
+ if (metaData.contains(QL1S("content-type")))
+ mimeType = metaData.value(QL1S("content-type"));
+
+ if (!mimeType.isEmpty())
+ return;
+
+ if (!reply->hasRawHeader("Content-Type"))
+ return;
+
+ const QString value (QL1S(reply->rawHeader("Content-Type").simplified().constData()));
+ const int index = value.indexOf(QL1C(';'));
+ if (index == -1)
+ mimeType = value;
+ else
+ mimeType = value.left(index);
+}
+
+
static bool downloadResource (const KUrl& srcUrl, const KIO::MetaData& metaData = KIO::MetaData(),
QWidget* parent = 0, const QString& suggestedName = QString())
{
@@ -237,6 +299,9 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &r
_isOnRekonqPage = false;
tab->setPart(0, KUrl()); // re-enable the view page
}
+
+ // reset webpage values
+ _suggestedFileName.clear();
_loadingUrl = request.url();
KIO::AccessManager *manager = qobject_cast<KIO::AccessManager*>(networkAccessManager());
@@ -289,15 +354,6 @@ bool WebPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &r
default:
break;
}
-
- if (frame == mainFrame())
- {
- setRequestMetaData("main_frame_request", "TRUE");
- }
- else
- {
- setRequestMetaData("main_frame_request", "FALSE");
- }
}
return KWebPage::acceptNavigationRequest(frame, request, type);
}
@@ -325,11 +381,10 @@ WebPage *WebPage::createWindow(QWebPage::WebWindowType type)
void WebPage::handleUnsupportedContent(QNetworkReply *reply)
{
Q_ASSERT (reply);
- // NOTE:
- // Until kio implements a way to resume/continue a network
- // request. We must abort the reply to prevent a zombie process
- // from continuing to download the unsupported content!
- reply->abort();
+
+ // Put the job on hold...
+ kDebug() << "PUT REPLY ON HOLD...";
+ KIO::Integration::AccessManager::putReplyOnHold(reply);
// This is probably needed just in ONE stupid case..
if (_protHandler.postHandling(reply->request(), mainFrame()))
@@ -338,78 +393,24 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
if (reply->error() != QNetworkReply::NoError)
return;
+ // get reply url...
KUrl replyUrl = reply->url();
- // HACK -------------------------------------------
- // This is done to fix #231204 && #212808
-
- QString mimeType;
- QString suggestedFileName;
+ // Get suggested file name...
+ extractSuggestedFileName(reply, _suggestedFileName);
- QString app = reply->header(QNetworkRequest::ContentTypeHeader).toString();
- QStringList headerList = app.split( ';' );
-
- if(headerList.count() > 0)
- {
- mimeType = headerList.takeFirst().trimmed();
- Q_FOREACH(const QString &head, headerList)
- {
- if( head.contains( QL1S("name") ) )
- {
- // this is not so sure.. :)
- suggestedFileName = head;
- suggestedFileName = suggestedFileName.remove( QL1S("name=") );
- suggestedFileName = suggestedFileName.remove( '"' );
- suggestedFileName = suggestedFileName.trimmed();
- break;
- }
- }
- }
- else
- {
- mimeType = reply->header(QNetworkRequest::ContentTypeHeader).toString();
- }
-
- // NOTE
- // This part has been copied from KWebPage::downloadResponse code
- if (reply->hasRawHeader("Content-Disposition"))
- {
- KIO::MetaData metaData = reply->attribute(static_cast<QNetworkRequest::Attribute>(KIO::AccessManager::MetaData)).toMap();
- if (metaData.value(QL1S("content-disposition-type")).compare(QL1S("attachment"), Qt::CaseInsensitive) == 0)
- {
- suggestedFileName = metaData.value(QL1S("content-disposition-filename"));
- }
- else
- {
- const QString value = QL1S(reply->rawHeader("Content-Disposition").simplified());
- if (value.startsWith(QL1S("attachment"), Qt::CaseInsensitive))
- {
- const int length = value.size();
- int pos = value.indexOf(QL1S("filename"), 0, Qt::CaseInsensitive);
- if (pos > -1)
- {
- pos += 9;
- while (pos < length && (value.at(pos) == QL1C(' ') || value.at(pos) == QL1C('=') || value.at(pos) == QL1C('"')))
- pos++;
-
- int endPos = pos;
- while (endPos < length && value.at(endPos) != QL1C('"') && value.at(endPos) != QL1C(';'))
- endPos++;
-
- if (endPos > pos)
- {
- suggestedFileName = value.mid(pos, (endPos-pos)).trimmed();
- }
- }
- }
- }
- }
-
- kDebug() << "Detected MimeType = " << mimeType;
- kDebug() << "Suggested File Name = " << suggestedFileName;
+ // Get mimeType...
+ extractMimeType(reply, _mimeType);
+
+ // Convert executable text files to plain text...
+ if (KParts::BrowserRun::isTextExecutable(_mimeType))
+ _mimeType = QL1S("text/plain");
+
+ kDebug() << "Detected MimeType = " << _mimeType;
+ kDebug() << "Suggested File Name = " << _suggestedFileName;
// ------------------------------------------------
- KService::Ptr appService = KMimeTypeTrader::self()->preferredService(mimeType);
+ KService::Ptr appService = KMimeTypeTrader::self()->preferredService(_mimeType);
bool isLocal = replyUrl.isLocalFile();
@@ -419,22 +420,22 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
isLocal
? KMessageBox::sorry(view(), i18n("No service can handle this file."))
- : downloadReply(reply, suggestedFileName);
+ : downloadReply(reply, _suggestedFileName);
return;
}
if (!isLocal)
{
- KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), replyUrl, mimeType);
- if(!suggestedFileName.isEmpty())
- dlg.setSuggestedFileName(suggestedFileName);
+ KParts::BrowserOpenOrSaveQuestion dlg(Application::instance()->mainWindow(), replyUrl, _mimeType);
+ if(!_suggestedFileName.isEmpty())
+ dlg.setSuggestedFileName(_suggestedFileName);
switch (dlg.askEmbedOrSave())
{
case KParts::BrowserOpenOrSaveQuestion::Save:
kDebug() << "user choice: no services, just download!";
- downloadReply(reply, suggestedFileName);
+ downloadReply(reply, _suggestedFileName);
return;
case KParts::BrowserOpenOrSaveQuestion::Cancel:
@@ -445,10 +446,46 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
}
}
+ // Handle Post operations that return content...
+ if (reply->operation() == QNetworkAccessManager::PostOperation)
+ {
+ kDebug() << "POST OPERATION: downloading file...";
+ QFileInfo finfo (_suggestedFileName.isEmpty() ? _loadingUrl.fileName() : _suggestedFileName);
+ KTemporaryFile tempFile;
+ tempFile.setSuffix(QL1C('.') + finfo.suffix());
+ tempFile.setAutoRemove(false);
+ tempFile.open();
+ KUrl destUrl;
+ destUrl.setPath(tempFile.fileName());
+ kDebug() << "First save content to" << destUrl;
+ KIO::Job *job = KIO::file_copy(_loadingUrl, destUrl, 0600, KIO::Overwrite);
+ job->ui()->setWindow(Application::instance()->mainWindow());
+ connect(job, SIGNAL(result(KJob *)), this, SLOT(copyToTempFileResult(KJob*)));
+ return;
+ }
+
+ // HACK: The check below is necessary to break an infinite
+ // recursion that occurs whenever this function is called as a result
+ // of receiving content that can be rendered by the app using this engine.
+ // For example a text/html header that containing a content-disposition
+ // header is received by the app using this class.
+ const QString& appName = QCoreApplication::applicationName();
+
+ if (appName == appService->desktopEntryName() || appService->exec().trimmed().startsWith(appName))
+ {
+ kDebug() << "SELF...";
+ QNetworkRequest req (reply->request());
+ req.setRawHeader("x-kdewebkit-ignore-disposition", "true");
+ currentFrame()->load(req);
+ return;
+ }
+
// case KParts::BrowserRun::Embed
- KParts::ReadOnlyPart *pa = KMimeTypeTrader::createPartInstanceFromQuery<KParts::ReadOnlyPart>(mimeType, view(), this, QString());
+ KParts::ReadOnlyPart *pa = KMimeTypeTrader::createPartInstanceFromQuery<KParts::ReadOnlyPart>(_mimeType, view(), this, QString());
if (pa)
{
+ kDebug() << "EMBEDDING CONTENT...";
+
_isOnRekonqPage = true;
WebView *view = qobject_cast<WebView *>(parent());
@@ -463,9 +500,21 @@ void WebPage::handleUnsupportedContent(QNetworkReply *reply)
else
{
// No parts, just app services. Load it!
- KRun::run(*appService, replyUrl, 0);
+ // If the app is a KDE one, publish the slave on hold to let it use it.
+ // Otherwise, run the app and remove it (the io slave...)
+ if (appService->categories().contains(QL1S("KDE"), Qt::CaseInsensitive))
+ {
+ KIO::Scheduler::publishSlaveOnHold();
+ KRun::run(*appService, replyUrl, 0, false, _suggestedFileName);
+ return;
+ }
+ KRun::run(*appService, replyUrl, 0, false, _suggestedFileName);
}
+ // Remove any ioslave that was put on hold...
+ kDebug() << "REMOVE SLAVES ON HOLD...";
+ KIO::Scheduler::removeSlaveOnHold();
+
return;
}
@@ -499,8 +548,6 @@ void WebPage::loadFinished(bool ok)
{
wallet()->fillFormData(mainFrame());
}
- kDebug() << "rekonq page: " << _isOnRekonqPage;
- kDebug() << "loading url: " << _loadingUrl;
}
@@ -508,6 +555,10 @@ void WebPage::manageNetworkErrors(QNetworkReply *reply)
{
Q_ASSERT(reply);
+ // check suggested file name
+ if(_suggestedFileName.isEmpty())
+ extractSuggestedFileName(reply, _suggestedFileName);
+
QWebFrame* frame = qobject_cast<QWebFrame *>(reply->request().originatingObject());
const bool isMainFrameRequest = (frame == mainFrame());
@@ -725,3 +776,12 @@ void WebPage::updateImage(bool ok)
p.snapFinished();
}
}
+
+
+void WebPage::copyToTempFileResult(KJob* job)
+{
+ if ( job->error() )
+ job->uiDelegate()->showErrorMessage();
+ else
+ (void)KRun::runUrl(static_cast<KIO::FileCopyJob *>(job)->destUrl(), _mimeType, Application::instance()->mainWindow());
+}
diff --git a/src/webpage.h b/src/webpage.h
index 41ddd877..7633b26d 100644
--- a/src/webpage.h
+++ b/src/webpage.h
@@ -59,6 +59,7 @@ public:
inline void setIsOnRekonqPage(bool b) { _isOnRekonqPage = b; };
inline KUrl loadingUrl() { return _loadingUrl; };
+ inline QString suggestedFileName() { return _suggestedFileName; };
public Q_SLOTS:
void downloadAllContentsWithKGet(QPoint);
@@ -81,15 +82,21 @@ private Q_SLOTS:
void showSSLInfo(QPoint);
void updateImage(bool ok);
+ void copyToTempFileResult(KJob*);
+
+private:
void downloadReply(const QNetworkReply *reply, const QString &suggestedFileName = QString());
private:
QString errorPage(QNetworkReply *reply);
- QUrl _loadingUrl;
+ KUrl _loadingUrl;
ProtocolHandler _protHandler;
WebSslInfo _sslInfo;
+ QString _mimeType;
+ QString _suggestedFileName;
+
bool _networkAnalyzer;
bool _isOnRekonqPage;
};