mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-24 04:24:09 +00:00
Add an option to enable saving resource files with articles (#321)
This commit is contained in:
parent
f4734c076c
commit
1ba03a326d
|
@ -486,7 +486,7 @@ void ArticleRequest::bodyFinished()
|
||||||
|
|
||||||
head += string( "<div class=\"gddictname\"><span class=\"gddicticon\"><img src=\"gico://")
|
head += string( "<div class=\"gddictname\"><span class=\"gddicticon\"><img src=\"gico://")
|
||||||
+ Html::escape( dictId )
|
+ Html::escape( dictId )
|
||||||
+ "/\"></span><span class=\"gdfromprefix\">" +
|
+ "/dicticon.png\"></span><span class=\"gdfromprefix\">" +
|
||||||
Html::escape( tr( "From " ).toUtf8().data() ) + "</span>" +
|
Html::escape( tr( "From " ).toUtf8().data() ) + "</span>" +
|
||||||
Html::escape( activeDict->getName().c_str() )
|
Html::escape( activeDict->getName().c_str() )
|
||||||
+ "</div>";
|
+ "</div>";
|
||||||
|
|
293
articleview.cc
293
articleview.cc
|
@ -22,6 +22,8 @@
|
||||||
#include <QWebElement>
|
#include <QWebElement>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
@ -952,10 +954,14 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArticleView::saveResource( const QUrl & url, QUrl const & ref )
|
vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, const QString & fileName )
|
||||||
{
|
{
|
||||||
resourceToSaveDownloadRequests.clear();
|
return saveResource( url, ui.definition->url(), fileName );
|
||||||
resourceToSaveUrl = url;
|
}
|
||||||
|
|
||||||
|
vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, const QUrl & ref, const QString & fileName )
|
||||||
|
{
|
||||||
|
vector< ResourceToSaveHandler * > handlers;
|
||||||
sptr< Dictionary::DataRequest > req;
|
sptr< Dictionary::DataRequest > req;
|
||||||
|
|
||||||
if( url.scheme() == "bres" || url.scheme() == "gico" || url.scheme() == "gdau")
|
if( url.scheme() == "bres" || url.scheme() == "gico" || url.scheme() == "gdau")
|
||||||
|
@ -989,25 +995,8 @@ void ArticleView::saveResource( const QUrl & url, QUrl const & ref )
|
||||||
req = (*activeDicts)[ x ]->getResource(
|
req = (*activeDicts)[ x ]->getResource(
|
||||||
url.path().mid( 1 ).toUtf8().data() );
|
url.path().mid( 1 ).toUtf8().data() );
|
||||||
|
|
||||||
if ( req->isFinished() && req->dataSize() >= 0 )
|
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName );
|
||||||
{
|
handlers.push_back( handler );
|
||||||
// A request was instantly finished with success.
|
|
||||||
// If we've managed to spawn some lingering requests already,
|
|
||||||
// erase them.
|
|
||||||
resourceToSaveDownloadRequests.clear();
|
|
||||||
|
|
||||||
// Handle the result
|
|
||||||
resourceToSaveDownloadRequests.push_back( req );
|
|
||||||
resourceToSaveDownloadFinished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ( !req->isFinished() )
|
|
||||||
{
|
|
||||||
resourceToSaveDownloadRequests.push_back( req );
|
|
||||||
connect( req.get(), SIGNAL( finished() ),
|
|
||||||
this, SLOT( resourceToSaveDownloadFinished() ), Qt::QueuedConnection );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1016,154 +1005,27 @@ void ArticleView::saveResource( const QUrl & url, QUrl const & ref )
|
||||||
// Normal resource download
|
// Normal resource download
|
||||||
QString contentType;
|
QString contentType;
|
||||||
req = articleNetMgr.getResource( url, contentType );
|
req = articleNetMgr.getResource( url, contentType );
|
||||||
|
|
||||||
|
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName );
|
||||||
|
handlers.push_back( handler );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
req = new Dictionary::WebMultimediaDownload( url, articleNetMgr );
|
req = new Dictionary::WebMultimediaDownload( url, articleNetMgr );
|
||||||
|
|
||||||
if( url.host().compare( "search" ) != 0 )
|
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName );
|
||||||
{
|
handlers.push_back( handler );
|
||||||
if ( !req.get() )
|
|
||||||
{
|
|
||||||
// Request failed, fail
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ( req->isFinished() && req->dataSize() >= 0 )
|
|
||||||
{
|
|
||||||
// Have data ready, handle it
|
|
||||||
resourceToSaveDownloadRequests.push_back( req );
|
|
||||||
resourceToSaveDownloadFinished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ( !req->isFinished() )
|
|
||||||
{
|
|
||||||
// Queue to be handled when done
|
|
||||||
|
|
||||||
resourceToSaveDownloadRequests.push_back( req );
|
|
||||||
connect( req.get(), SIGNAL( finished() ),
|
|
||||||
this, SLOT( resourceToSaveDownloadFinished() ), Qt::QueuedConnection );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( resourceToSaveDownloadRequests.empty() ) // No requests were queued
|
if ( handlers.empty() ) // No requests were queued
|
||||||
{
|
{
|
||||||
emit statusBarMessage(
|
emit statusBarMessage(
|
||||||
tr( "ERROR: %1" ).arg( tr( "The referenced resource doesn't exist." ) ),
|
tr( "ERROR: %1" ).arg( tr( "The referenced resource doesn't exist." ) ),
|
||||||
10000, QPixmap( ":/icons/error.png" ) );
|
10000, QPixmap( ":/icons/error.png" ) );
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
resourceToSaveDownloadFinished(); // Check any requests finished already
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArticleView::resourceToSaveDownloadFinished()
|
return handlers;
|
||||||
{
|
|
||||||
if ( resourceToSaveDownloadRequests.empty() )
|
|
||||||
return; // Stray signal
|
|
||||||
|
|
||||||
QByteArray resourceData;
|
|
||||||
|
|
||||||
// Find any finished resources
|
|
||||||
|
|
||||||
for( list< sptr< Dictionary::DataRequest > >::iterator i =
|
|
||||||
resourceToSaveDownloadRequests.begin(); i != resourceToSaveDownloadRequests.end(); )
|
|
||||||
{
|
|
||||||
if ( (*i)->isFinished() )
|
|
||||||
{
|
|
||||||
if ( (*i)->dataSize() >= 0 )
|
|
||||||
{
|
|
||||||
// Ok, got one finished, all others are irrelevant now
|
|
||||||
|
|
||||||
vector< char > const & data = (*i)->getFullData();
|
|
||||||
resourceData = QByteArray( data.data(), data.size() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This one had no data. Erase it.
|
|
||||||
resourceToSaveDownloadRequests.erase( i++ );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // Unfinished, try the next one.
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !resourceData.isEmpty() )
|
|
||||||
{
|
|
||||||
// Resource found, clear all requests
|
|
||||||
resourceToSaveDownloadRequests.clear();
|
|
||||||
|
|
||||||
QString fileName;
|
|
||||||
QString savePath;
|
|
||||||
if( cfg.resourceSavePath.isEmpty() )
|
|
||||||
savePath = QDir::homePath();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
savePath = QDir::fromNativeSeparators( cfg.resourceSavePath );
|
|
||||||
if( !QDir( savePath ).exists() )
|
|
||||||
savePath = QDir::homePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString name = resourceToSaveUrl.path().section( '/', -1 );
|
|
||||||
|
|
||||||
if ( resourceToSaveUrl.scheme() == "gdau" ||
|
|
||||||
Dictionary::WebMultimediaDownload::isAudioUrl( resourceToSaveUrl ) )
|
|
||||||
{
|
|
||||||
// Audio data
|
|
||||||
if( name.indexOf( '.' ) < 0 )
|
|
||||||
name += ".wav";
|
|
||||||
|
|
||||||
fileName = savePath + "/" + name;
|
|
||||||
fileName = QFileDialog::getSaveFileName( parentWidget(), tr( "Save sound" ),
|
|
||||||
fileName,
|
|
||||||
tr( "Sound files (*.wav *.ogg *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)" ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Image data
|
|
||||||
|
|
||||||
// Check for babylon image name
|
|
||||||
if( name[ 0 ] == '\x1E' )
|
|
||||||
name.remove( 0, 1 );
|
|
||||||
if( name[ name.length() - 1 ] == '\x1F' )
|
|
||||||
name.chop( 1 );
|
|
||||||
|
|
||||||
fileName = savePath + "/" + name;
|
|
||||||
fileName = QFileDialog::getSaveFileName( parentWidget(), tr( "Save image" ),
|
|
||||||
fileName,
|
|
||||||
tr( "Image files (*.bmp *.jpg *.png *.tif);;All files (*.*)" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write data to file
|
|
||||||
|
|
||||||
if( !fileName.isEmpty() )
|
|
||||||
{
|
|
||||||
QFileInfo fileInfo( fileName );
|
|
||||||
emit storeResourceSavePath( QDir::toNativeSeparators( fileInfo.absoluteDir().absolutePath() ) );
|
|
||||||
QFile file( fileName );
|
|
||||||
if ( file.open( QFile::WriteOnly ) )
|
|
||||||
{
|
|
||||||
file.write( resourceData.data(), resourceData.size() );
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
if( file.error() )
|
|
||||||
{
|
|
||||||
emit statusBarMessage(
|
|
||||||
tr( "ERROR: %1" ).arg( tr( "Resource saving error: " ) + file.errorString() ),
|
|
||||||
10000, QPixmap( ":/icons/error.png" ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( resourceToSaveDownloadRequests.empty() )
|
|
||||||
{
|
|
||||||
emit statusBarMessage(
|
|
||||||
tr( "ERROR: %1" ).arg( tr( "The referenced resource failed to download." ) ),
|
|
||||||
10000, QPixmap( ":/icons/error.png" ) );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArticleView::updateMutedContents()
|
void ArticleView::updateMutedContents()
|
||||||
|
@ -1499,11 +1361,57 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
|
||||||
emit showDefinitionInNewTab( selectedText, groupComboBox->getCurrentGroup(),
|
emit showDefinitionInNewTab( selectedText, groupComboBox->getCurrentGroup(),
|
||||||
QString(), Contexts() );
|
QString(), Contexts() );
|
||||||
else
|
else
|
||||||
if( result == saveImageAction )
|
if( result == saveImageAction || result == saveSoundAction )
|
||||||
saveResource( imageUrl, ui.definition->url() );
|
{
|
||||||
|
QUrl url = ( result == saveImageAction ) ? imageUrl : targetUrl;
|
||||||
|
QString savePath;
|
||||||
|
QString fileName;
|
||||||
|
|
||||||
|
if ( cfg.resourceSavePath.isEmpty() )
|
||||||
|
savePath = QDir::homePath();
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
savePath = QDir::fromNativeSeparators( cfg.resourceSavePath );
|
||||||
|
if ( !QDir( savePath ).exists() )
|
||||||
|
savePath = QDir::homePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString name = url.path().section( '/', -1 );
|
||||||
|
|
||||||
if ( result == saveSoundAction )
|
if ( result == saveSoundAction )
|
||||||
saveResource( targetUrl, ui.definition->url() );
|
{
|
||||||
|
// Audio data
|
||||||
|
if ( name.indexOf( '.' ) < 0 )
|
||||||
|
name += ".wav";
|
||||||
|
|
||||||
|
fileName = savePath + "/" + name;
|
||||||
|
fileName = QFileDialog::getSaveFileName( parentWidget(), tr( "Save sound" ),
|
||||||
|
fileName,
|
||||||
|
tr( "Sound files (*.wav *.ogg *.mp3 *.mp4 *.aac *.flac *.mid *.wv *.ape);;All files (*.*)" ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Image data
|
||||||
|
|
||||||
|
// Check for babylon image name
|
||||||
|
if ( name[ 0 ] == '\x1E' )
|
||||||
|
name.remove( 0, 1 );
|
||||||
|
if ( name.length() && name[ name.length() - 1 ] == '\x1F' )
|
||||||
|
name.chop( 1 );
|
||||||
|
|
||||||
|
fileName = savePath + "/" + name;
|
||||||
|
fileName = QFileDialog::getSaveFileName( parentWidget(), tr( "Save image" ),
|
||||||
|
fileName,
|
||||||
|
tr( "Image files (*.bmp *.jpg *.png *.tif);;All files (*.*)" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !fileName.isEmpty() )
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo( fileName );
|
||||||
|
emit storeResourceSavePath( QDir::toNativeSeparators( fileInfo.absoluteDir().absolutePath() ) );
|
||||||
|
saveResource( url, ui.definition->url(), fileName );
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( !popupView && result == maxDictionaryRefsAction )
|
if ( !popupView && result == maxDictionaryRefsAction )
|
||||||
|
@ -2147,3 +2055,68 @@ QString ArticleView::wordAtPoint( int x, int y )
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ResourceToSaveHandler::ResourceToSaveHandler(
|
||||||
|
ArticleView * view, sptr< Dictionary::DataRequest > req,
|
||||||
|
QString const & fileName ) :
|
||||||
|
QObject( view ),
|
||||||
|
req( req ),
|
||||||
|
fileName( fileName )
|
||||||
|
{
|
||||||
|
connect( this, SIGNAL( statusBarMessage( QString, int, QPixmap ) ),
|
||||||
|
view, SIGNAL( statusBarMessage( QString, int, QPixmap ) ) );
|
||||||
|
|
||||||
|
// If DataRequest finsihed immediately, call our handler directly
|
||||||
|
if ( req.get()->isFinished() )
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod( this, "downloadFinished", Qt::QueuedConnection );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connect( req.get(), SIGNAL( finished() ), this, SLOT( downloadFinished() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceToSaveHandler::downloadFinished()
|
||||||
|
{
|
||||||
|
assert( req && req.get()->isFinished() );
|
||||||
|
|
||||||
|
QByteArray resourceData;
|
||||||
|
|
||||||
|
if ( req.get()->dataSize() >= 0 )
|
||||||
|
{
|
||||||
|
vector< char > const & data = req.get()->getFullData();
|
||||||
|
resourceData = QByteArray( data.data(), data.size() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data to file
|
||||||
|
|
||||||
|
if ( !resourceData.isEmpty() && !fileName.isEmpty() )
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo( fileName );
|
||||||
|
QDir().mkpath( fileInfo.absoluteDir().absolutePath() );
|
||||||
|
|
||||||
|
QFile file( fileName );
|
||||||
|
if ( file.open( QFile::WriteOnly ) )
|
||||||
|
{
|
||||||
|
file.write( resourceData.data(), resourceData.size() );
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( file.error() )
|
||||||
|
{
|
||||||
|
emit statusBarMessage(
|
||||||
|
tr( "ERROR: %1" ).arg( tr( "Resource saving error: " ) + file.errorString() ),
|
||||||
|
10000, QPixmap( ":/icons/error.png" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emit statusBarMessage(
|
||||||
|
tr( "ERROR: %1" ).arg( tr( "The referenced resource failed to download." ) ),
|
||||||
|
10000, QPixmap( ":/icons/error.png" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
emit done();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#include "groupcombobox.hh"
|
#include "groupcombobox.hh"
|
||||||
#include "ui_articleview.h"
|
#include "ui_articleview.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ResourceToSaveHandler;
|
||||||
|
|
||||||
/// A widget with the web view tailored to view and handle articles -- it
|
/// A widget with the web view tailored to view and handle articles -- it
|
||||||
/// uses the appropriate netmgr, handles link clicks, rmb clicks etc
|
/// uses the appropriate netmgr, handles link clicks, rmb clicks etc
|
||||||
class ArticleView: public QFrame
|
class ArticleView: public QFrame
|
||||||
|
@ -42,9 +45,6 @@ class ArticleView: public QFrame
|
||||||
/// Url of the resourceDownloadRequests
|
/// Url of the resourceDownloadRequests
|
||||||
QUrl resourceDownloadUrl;
|
QUrl resourceDownloadUrl;
|
||||||
|
|
||||||
std::list< sptr< Dictionary::DataRequest > > resourceToSaveDownloadRequests;
|
|
||||||
QUrl resourceToSaveUrl;
|
|
||||||
|
|
||||||
/// For resources opened via desktop services
|
/// For resources opened via desktop services
|
||||||
QString desktopOpenedTempFile;
|
QString desktopOpenedTempFile;
|
||||||
|
|
||||||
|
@ -162,6 +162,9 @@ public:
|
||||||
/// Returns the dictionary id of the currently active article in the view.
|
/// Returns the dictionary id of the currently active article in the view.
|
||||||
QString getActiveArticleId();
|
QString getActiveArticleId();
|
||||||
|
|
||||||
|
std::vector< ResourceToSaveHandler * > saveResource( const QUrl & url, const QString & fileName );
|
||||||
|
std::vector< ResourceToSaveHandler * > saveResource( const QUrl & url, const QUrl & ref, const QString & fileName );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void iconChanged( ArticleView *, QIcon const & icon );
|
void iconChanged( ArticleView *, QIcon const & icon );
|
||||||
|
@ -238,7 +241,6 @@ private slots:
|
||||||
void contextMenuRequested( QPoint const & );
|
void contextMenuRequested( QPoint const & );
|
||||||
|
|
||||||
void resourceDownloadFinished();
|
void resourceDownloadFinished();
|
||||||
void resourceToSaveDownloadFinished();
|
|
||||||
|
|
||||||
/// We handle pasting by attempting to define the word in clipboard.
|
/// We handle pasting by attempting to define the word in clipboard.
|
||||||
void pasteTriggered();
|
void pasteTriggered();
|
||||||
|
@ -315,8 +317,6 @@ private:
|
||||||
/// for the given group. If there are none, returns empty string.
|
/// for the given group. If there are none, returns empty string.
|
||||||
QString getMutedForGroup( unsigned group );
|
QString getMutedForGroup( unsigned group );
|
||||||
|
|
||||||
void saveResource( QUrl const &, QUrl const & );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// We need this to hide the search bar when we're showed
|
// We need this to hide the search bar when we're showed
|
||||||
|
@ -336,4 +336,24 @@ public:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ResourceToSaveHandler: public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ResourceToSaveHandler( ArticleView * view, sptr< Dictionary::DataRequest > req,
|
||||||
|
QString const & fileName );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void done();
|
||||||
|
void statusBarMessage( QString const & message, int timeout = 0, QPixmap const & pixmap = QPixmap() );
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void downloadFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
sptr< Dictionary::DataRequest > req;
|
||||||
|
QString fileName;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "fsencoding.hh"
|
#include "fsencoding.hh"
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include "historypanewidget.hh"
|
#include "historypanewidget.hh"
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
#include "lionsupport.h"
|
#include "lionsupport.h"
|
||||||
|
@ -2879,6 +2880,39 @@ void MainWindow::printPreviewPaintRequested( QPrinter * printer )
|
||||||
view->print( printer );
|
view->print( printer );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void filterAndCollectResources( QString & html, QRegExp & rx, const QString & sep,
|
||||||
|
const QString & folder, set< QByteArray > & resourceIncluded,
|
||||||
|
vector< pair< QUrl, QString > > & downloadResources )
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while ( ( pos = rx.indexIn( html, pos ) ) != -1 )
|
||||||
|
{
|
||||||
|
QUrl url( rx.cap( 1 ) );
|
||||||
|
QString host = url.host();
|
||||||
|
QString resourcePath = QString::fromLatin1( QUrl::toPercentEncoding( url.path(), "/" ) );
|
||||||
|
|
||||||
|
if ( !host.startsWith( '/' ) )
|
||||||
|
host.insert( 0, '/' );
|
||||||
|
if ( !resourcePath.startsWith( '/' ) )
|
||||||
|
resourcePath.insert( 0, '/' );
|
||||||
|
|
||||||
|
QCryptographicHash hash( QCryptographicHash::Md5 );
|
||||||
|
hash.addData( rx.cap().toUtf8() );
|
||||||
|
|
||||||
|
if ( resourceIncluded.insert( hash.result() ).second )
|
||||||
|
{
|
||||||
|
// Gather resouce information (url, filename) to be download later
|
||||||
|
downloadResources.push_back( pair<QUrl, QString>( url, folder + host + resourcePath ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify original url, set to the native one
|
||||||
|
QString newUrl = sep + QDir( folder ).dirName() + host + resourcePath + sep;
|
||||||
|
html.replace( pos, rx.cap().length(), newUrl );
|
||||||
|
pos += newUrl.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_saveArticle_triggered()
|
void MainWindow::on_saveArticle_triggered()
|
||||||
{
|
{
|
||||||
ArticleView *view = getCurrentArticleView();
|
ArticleView *view = getCurrentArticleView();
|
||||||
|
@ -2895,10 +2929,19 @@ void MainWindow::on_saveArticle_triggered()
|
||||||
savePath = QDir::homePath();
|
savePath = QDir::homePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFileDialog::Options options = QFileDialog::HideNameFilterDetails;
|
||||||
|
QString selectedFilter;
|
||||||
|
QStringList filters;
|
||||||
|
filters.push_back( tr( "Article, Complete (*.html)" ) );
|
||||||
|
filters.push_back( tr( "Article, HTML Only (*.html)" ) );
|
||||||
|
|
||||||
fileName = savePath + "/" + fileName;
|
fileName = savePath + "/" + fileName;
|
||||||
fileName = QFileDialog::getSaveFileName( this, tr( "Save Article As" ),
|
fileName = QFileDialog::getSaveFileName( this, tr( "Save Article As" ),
|
||||||
fileName,
|
fileName,
|
||||||
tr( "Html files (*.html *.htm)" ) );
|
filters.join( ";;" ),
|
||||||
|
&selectedFilter, options );
|
||||||
|
|
||||||
|
bool complete = ( selectedFilter == filters[ 0 ] );
|
||||||
|
|
||||||
if ( !fileName.isEmpty() )
|
if ( !fileName.isEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -2912,8 +2955,51 @@ void MainWindow::on_saveArticle_triggered()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
file.write( view->toHtml().toUtf8() );
|
QString html = view->toHtml();
|
||||||
cfg.articleSavePath = QDir::toNativeSeparators( QFileInfo( fileName ).absoluteDir().absolutePath() );
|
QFileInfo fi( fileName );
|
||||||
|
cfg.articleSavePath = QDir::toNativeSeparators( fi.absoluteDir().absolutePath() );
|
||||||
|
|
||||||
|
if ( complete )
|
||||||
|
{
|
||||||
|
QString folder = fi.absoluteDir().absolutePath() + "/" + fi.baseName() + "_files";
|
||||||
|
QRegExp rx1( "\"((?:bres|gico|gdau|qrcx)://[^\"]+)\"" );
|
||||||
|
QRegExp rx2( "'((?:bres|gico|gdau|qrcx)://[^']+)'" );
|
||||||
|
set< QByteArray > resourceIncluded;
|
||||||
|
vector< pair< QUrl, QString > > downloadResources;
|
||||||
|
|
||||||
|
filterAndCollectResources( html, rx1, "\"", folder, resourceIncluded, downloadResources );
|
||||||
|
filterAndCollectResources( html, rx2, "'", folder, resourceIncluded, downloadResources );
|
||||||
|
|
||||||
|
ArticleSaveProgressDialog * progressDialog = new ArticleSaveProgressDialog( this );
|
||||||
|
// reserve '1' for saving main html file
|
||||||
|
int maxVal = 1;
|
||||||
|
|
||||||
|
// Pull and save resources to files
|
||||||
|
for ( vector< pair< QUrl, QString > >::const_iterator i = downloadResources.begin();
|
||||||
|
i != downloadResources.end(); i++ )
|
||||||
|
{
|
||||||
|
vector< ResourceToSaveHandler * > handlerss = view->saveResource( i->first, i->second );
|
||||||
|
maxVal += handlerss.size();
|
||||||
|
|
||||||
|
for ( vector< ResourceToSaveHandler * >::iterator j = handlerss.begin();
|
||||||
|
j != handlerss.end(); j++ )
|
||||||
|
{
|
||||||
|
connect( *j, SIGNAL( done() ), progressDialog, SLOT( perform() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progressDialog->setLabelText( tr("Saving article...") );
|
||||||
|
progressDialog->setRange( 0, maxVal );
|
||||||
|
progressDialog->setValue( 0 );
|
||||||
|
progressDialog->show();
|
||||||
|
|
||||||
|
file.write( html.toUtf8() );
|
||||||
|
progressDialog->setValue( 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file.write( html.toUtf8() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <QToolButton>
|
#include <QToolButton>
|
||||||
#include <QSystemTrayIcon>
|
#include <QSystemTrayIcon>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QProgressDialog>
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "folding.hh"
|
#include "folding.hh"
|
||||||
#include "config.hh"
|
#include "config.hh"
|
||||||
|
@ -410,4 +411,29 @@ private slots:
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ArticleSaveProgressDialog : public QProgressDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ArticleSaveProgressDialog( QWidget * parent = 0, Qt::WindowFlags f = 0 ):
|
||||||
|
QProgressDialog( parent, f )
|
||||||
|
{
|
||||||
|
setAutoReset( false );
|
||||||
|
setAutoClose( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void perform()
|
||||||
|
{
|
||||||
|
int progress = value() + 1;
|
||||||
|
if ( progress == maximum() )
|
||||||
|
{
|
||||||
|
emit close();
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
setValue( progress );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue