Refactor resource downloading

This commit is contained in:
Abs62 2017-04-27 23:55:53 +03:00
parent 67b6b6b91c
commit 747dc0aaaf
3 changed files with 93 additions and 92 deletions

View file

@ -1165,6 +1165,7 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
activeDicts = &allDictionaries; activeDicts = &allDictionaries;
if ( activeDicts ) if ( activeDicts )
{
for( unsigned x = 0; x < activeDicts->size(); ++x ) for( unsigned x = 0; x < activeDicts->size(); ++x )
{ {
try try
@ -1173,24 +1174,10 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
(*activeDicts)[ x ]->getResource( (*activeDicts)[ x ]->getResource(
url.path().mid( 1 ).toUtf8().data() ); url.path().mid( 1 ).toUtf8().data() );
if ( req->isFinished() && req->dataSize() >= 0 ) resourceDownloadRequests.push_back( req );
{
// A request was instantly finished with success.
// If we've managed to spawn some lingering requests already,
// erase them.
resourceDownloadRequests.clear();
// Handle the result
resourceDownloadRequests.push_back( req );
resourceDownloadFinished();
return;
}
else
if ( !req->isFinished() ) if ( !req->isFinished() )
{ {
resourceDownloadRequests.push_back( req );
connect( req.get(), SIGNAL( finished() ), connect( req.get(), SIGNAL( finished() ),
this, SLOT( resourceDownloadFinished() ) ); this, SLOT( resourceDownloadFinished() ) );
} }
@ -1202,6 +1189,7 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
10000, QPixmap( ":/icons/error.png" ) ); 10000, QPixmap( ":/icons/error.png" ) );
} }
} }
}
} }
else else
{ {
@ -1314,14 +1302,14 @@ void ArticleView::openLink( QUrl const & url, QUrl const & ref,
} }
} }
vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, const QString & fileName ) ResourceToSaveHandler * ArticleView::saveResource( const QUrl & url, const QString & fileName )
{ {
return saveResource( url, ui.definition->url(), fileName ); return saveResource( url, ui.definition->url(), fileName );
} }
vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, const QUrl & ref, const QString & fileName ) ResourceToSaveHandler * ArticleView::saveResource( const QUrl & url, const QUrl & ref, const QString & fileName )
{ {
vector< ResourceToSaveHandler * > handlers; ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, fileName );
sptr< Dictionary::DataRequest > req; sptr< Dictionary::DataRequest > req;
if( url.scheme() == "bres" || url.scheme() == "gico" || url.scheme() == "gdau" || url.scheme() == "gdvideo" ) if( url.scheme() == "bres" || url.scheme() == "gico" || url.scheme() == "gdau" || url.scheme() == "gdvideo" )
@ -1357,14 +1345,7 @@ vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, c
req = (*activeDicts)[ x ]->getResource( req = (*activeDicts)[ x ]->getResource(
Qt4x5::Url::path( url ).mid( 1 ).toUtf8().data() ); Qt4x5::Url::path( url ).mid( 1 ).toUtf8().data() );
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName, true ); handler->addRequest( req );
handlers.push_back( handler );
if( req.get()->isFinished() && req.get()->dataSize() > 0 )
{
// A request was instantly finished with success. Stop search.
return handlers;
}
} }
catch( std::exception & e ) catch( std::exception & e )
{ {
@ -1382,8 +1363,7 @@ vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, c
if( req.get() ) if( req.get() )
{ {
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName ); handler->addRequest( req );
handlers.push_back( handler );
} }
} }
} }
@ -1391,18 +1371,20 @@ vector< ResourceToSaveHandler * > ArticleView::saveResource( const QUrl & url, c
{ {
req = new Dictionary::WebMultimediaDownload( url, articleNetMgr ); req = new Dictionary::WebMultimediaDownload( url, articleNetMgr );
ResourceToSaveHandler * handler = new ResourceToSaveHandler( this, req, fileName ); handler->addRequest( req );
handlers.push_back( handler );
} }
if ( handlers.empty() ) // No requests were queued if ( handler->isEmpty() ) // 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 handlers; // Check already finished downloads
handler->downloadFinished();
return handler;
} }
void ArticleView::updateMutedContents() void ArticleView::updateMutedContents()
@ -1927,8 +1909,8 @@ void ArticleView::resourceDownloadFinished()
resourceDownloadRequests.erase( i++ ); resourceDownloadRequests.erase( i++ );
} }
} }
else // Unfinished, try the next one. else // Unfinished, wait.
i++; break;
} }
if ( resourceDownloadRequests.empty() ) if ( resourceDownloadRequests.empty() )
@ -2747,71 +2729,90 @@ QString ArticleView::wordAtPoint( int x, int y )
#endif #endif
ResourceToSaveHandler::ResourceToSaveHandler( ResourceToSaveHandler::ResourceToSaveHandler(ArticleView * view, QString const & fileName ) :
ArticleView * view, sptr< Dictionary::DataRequest > req,
QString const & fileName, bool search ) :
QObject( view ), QObject( view ),
req( req ),
fileName( fileName ), fileName( fileName ),
search_req( search ) alreadyDone( false )
{ {
connect( this, SIGNAL( statusBarMessage( QString, int, QPixmap ) ), connect( this, SIGNAL( statusBarMessage( QString, int, QPixmap ) ),
view, SIGNAL( statusBarMessage( QString, int, QPixmap ) ) ); view, SIGNAL( statusBarMessage( QString, int, QPixmap ) ) );
}
// If DataRequest finsihed immediately, call our handler directly void ResourceToSaveHandler::addRequest( sptr<Dictionary::DataRequest> req )
if ( req.get()->isFinished() ) {
if( !alreadyDone )
{ {
QMetaObject::invokeMethod( this, "downloadFinished", Qt::QueuedConnection ); downloadRequests.push_back( req );
}
else connect( req.get(), SIGNAL( finished() ),
{ this, SLOT( downloadFinished() ) );
connect( req.get(), SIGNAL( finished() ), this, SLOT( downloadFinished() ) );
} }
} }
void ResourceToSaveHandler::downloadFinished() void ResourceToSaveHandler::downloadFinished()
{ {
assert( req && req.get()->isFinished() ); if ( downloadRequests.empty() )
return; // Stray signal
QByteArray resourceData; // Find any finished resources
for( list< sptr< Dictionary::DataRequest > >::iterator i =
if ( req.get()->dataSize() >= 0 ) downloadRequests.begin(); i != downloadRequests.end(); )
{ {
vector< char > const & data = req.get()->getFullData(); if ( (*i)->isFinished() )
resourceData = QByteArray( data.data(), data.size() ); {
if ( (*i)->dataSize() >= 0 && !alreadyDone )
{
QByteArray resourceData;
vector< char > const & data = (*i)->getFullData();
resourceData = QByteArray( data.data(), data.size() );
// Write data to file
if ( !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" ) );
}
}
alreadyDone = true;
// Clear other requests
downloadRequests.clear();
break;
}
else
{
// This one had no data. Erase it.
downloadRequests.erase( i++ );
}
}
else // Unfinished, wait.
break;
} }
// Write data to file if ( downloadRequests.empty() )
if ( !resourceData.isEmpty() && !fileName.isEmpty() )
{ {
QFileInfo fileInfo( fileName ); if( !alreadyDone )
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( emit statusBarMessage(
tr( "ERROR: %1" ).arg( tr( "Resource saving error: " ) + file.errorString() ), tr( "WARNING: %1" ).arg( tr( "The referenced resource failed to download." ) ),
10000, QPixmap( ":/icons/error.png" ) ); 10000, QPixmap( ":/icons/error.png" ) );
} }
emit done();
deleteLater();
} }
else
{
if( !search_req )
{
emit statusBarMessage(
tr( "ERROR: %1" ).arg( tr( "The referenced resource failed to download." ) ),
10000, QPixmap( ":/icons/error.png" ) );
}
}
emit done();
deleteLater();
} }

View file

@ -177,8 +177,8 @@ 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 ); ResourceToSaveHandler * saveResource( const QUrl & url, const QString & fileName );
std::vector< ResourceToSaveHandler * > saveResource( const QUrl & url, const QUrl & ref, const QString & fileName ); ResourceToSaveHandler * saveResource( const QUrl & url, const QUrl & ref, const QString & fileName );
signals: signals:
@ -365,20 +365,22 @@ class ResourceToSaveHandler: public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ResourceToSaveHandler( ArticleView * view, sptr< Dictionary::DataRequest > req, explicit ResourceToSaveHandler( ArticleView * view, QString const & fileName );
QString const & fileName, bool search = false ); void addRequest( sptr< Dictionary::DataRequest > req );
bool isEmpty()
{ return downloadRequests.empty(); }
signals: signals:
void done(); void done();
void statusBarMessage( QString const & message, int timeout = 0, QPixmap const & pixmap = QPixmap() ); void statusBarMessage( QString const & message, int timeout = 0, QPixmap const & pixmap = QPixmap() );
private slots: public slots:
void downloadFinished(); void downloadFinished();
private: private:
sptr< Dictionary::DataRequest > req; std::list< sptr< Dictionary::DataRequest > > downloadRequests;
QString fileName; QString fileName;
bool search_req; bool alreadyDone;
}; };
#endif #endif

View file

@ -3362,13 +3362,11 @@ void MainWindow::on_saveArticle_triggered()
for ( vector< pair< QUrl, QString > >::const_iterator i = downloadResources.begin(); for ( vector< pair< QUrl, QString > >::const_iterator i = downloadResources.begin();
i != downloadResources.end(); i++ ) i != downloadResources.end(); i++ )
{ {
vector< ResourceToSaveHandler * > handlerss = view->saveResource( i->first, i->second ); ResourceToSaveHandler * handler = view->saveResource( i->first, i->second );
maxVal += handlerss.size(); if( !handler->isEmpty() )
for ( vector< ResourceToSaveHandler * >::iterator j = handlerss.begin();
j != handlerss.end(); j++ )
{ {
connect( *j, SIGNAL( done() ), progressDialog, SLOT( perform() ) ); maxVal += 1;
connect( handler, SIGNAL( done() ), progressDialog, SLOT( perform() ) );
} }
} }