18 #include <QTemporaryFile>
22 #include <QFutureWatcher>
23 #include <QtConcurrentRun>
24 #include <QProcessEnvironment>
25 #include <QMutexLocker>
27 #include <QNetworkAccessManager>
28 #include <QNetworkReply>
29 #include <QDomDocument>
43 QString m_releaseDate;
47 QDomNode m_registryNode;
49 qint64 m_downloadedSize;
53 QString installedVersion()
const;
54 QString installedReleaseDate()
const;
55 bool isUpgradable()
const;
56 QStringList installedFiles()
const;
58 static bool deeperThan(
const QString &one,
const QString &two );
61 class FetchPreviewJob;
63 class NewstuffModelPrivate
76 typedef QPair<int, UserAction> Action;
78 NewstuffModel* m_parent;
80 QVector<NewstuffItem> m_items;
82 QNetworkAccessManager m_networkAccessManager;
86 QMap<QNetworkReply *, FetchPreviewJob *> m_networkJobs;
88 QNetworkReply* m_currentReply;
90 QTemporaryFile* m_currentFile;
92 QString m_targetDirectory;
94 QString m_registryFile;
98 QDomDocument m_registryDocument;
102 Action m_currentAction;
104 QProcess* m_unpackProcess;
108 QList<Action> m_actionQueue;
110 #if QT_VERSION >= 0x050000
111 QHash<int, QByteArray> m_roleNames;
114 NewstuffModelPrivate( NewstuffModel* parent );
116 QIcon preview(
int index );
117 void setPreview(
int index,
const QIcon &previewIcon );
119 void handleProviderData( QNetworkReply* reply );
121 bool canExecute(
const QString &executable )
const;
129 void uninstall(
int index );
131 void changeNode( QDomNode &node, QDomDocument &domDocument,
const QString &key,
const QString &value, NodeAction action );
133 void readInstalledFiles( QStringList* target,
const QDomNode &node );
137 NewstuffItem importNode(
const QDomNode &node )
const;
139 bool isTransitioning(
int index )
const;
142 void readValue(
const QDomNode &node,
const QString &key, T* target )
const;
145 class FetchPreviewJob
148 FetchPreviewJob( NewstuffModelPrivate *modelPrivate,
int index );
150 void run(
const QByteArray &data );
153 NewstuffModelPrivate *
const m_modelPrivate;
157 NewstuffItem::NewstuffItem() : m_payloadSize( -2 ), m_downloadedSize( 0 )
162 QString NewstuffItem::installedVersion()
const
164 QDomNodeList
const nodes = m_registryNode.toElement().elementsByTagName(
"version" );
165 if ( nodes.size() == 1 ) {
166 return nodes.at( 0 ).toElement().text();
172 QString NewstuffItem::installedReleaseDate()
const
174 QDomNodeList
const nodes = m_registryNode.toElement().elementsByTagName(
"releasedate" );
175 if ( nodes.size() == 1 ) {
176 return nodes.at( 0 ).toElement().text();
182 bool NewstuffItem::isUpgradable()
const
184 bool installedOk, remoteOk;
185 double const installed = installedVersion().toDouble( &installedOk );
186 double const remote= m_version.toDouble( &remoteOk );
187 return installedOk && remoteOk && remote > installed;
190 QStringList NewstuffItem::installedFiles()
const
193 QDomNodeList
const nodes = m_registryNode.toElement().elementsByTagName(
"installedfile" );
194 for (
int i=0; i<nodes.count(); ++i ) {
195 result << nodes.at( i ).toElement().text();
200 bool NewstuffItem::deeperThan(
const QString &one,
const QString &two)
202 return one.length() > two.length();
205 FetchPreviewJob::FetchPreviewJob( NewstuffModelPrivate *modelPrivate,
int index ) :
206 m_modelPrivate( modelPrivate ),
211 void FetchPreviewJob::run(
const QByteArray &data )
213 const QImage image = QImage::fromData( data );
215 if ( image.isNull() )
218 const QPixmap pixmap = QPixmap::fromImage( image );
219 const QIcon previewIcon( pixmap );
220 m_modelPrivate->setPreview( m_index, previewIcon );
223 NewstuffModelPrivate::NewstuffModelPrivate( NewstuffModel* parent ) : m_parent( parent ),
224 m_networkAccessManager( 0 ), m_currentReply( 0 ), m_currentFile( 0 ),
225 m_idTag( NewstuffModel::PayloadTag ), m_currentAction( -1, Install ), m_unpackProcess( 0 )
230 QIcon NewstuffModelPrivate::preview(
int index )
232 if ( m_items.at( index ).m_preview.isNull() ) {
233 QPixmap dummyPixmap( 136, 136 );
234 dummyPixmap.fill( Qt::transparent );
235 setPreview( index, QIcon( dummyPixmap ) );
236 QNetworkReply *reply = m_networkAccessManager.get( QNetworkRequest( m_items.at( index ).m_previewUrl ) );
237 m_networkJobs.insert( reply,
new FetchPreviewJob(
this, index ) );
240 Q_ASSERT( !m_items.at( index ).m_preview.isNull() );
242 return m_items.at( index ).m_preview;
245 void NewstuffModelPrivate::setPreview(
int index,
const QIcon &previewIcon )
247 NewstuffItem &item = m_items[index];
248 item.m_preview = previewIcon;
249 const QModelIndex affected = m_parent->index( index );
250 emit m_parent->dataChanged( affected, affected );
253 void NewstuffModelPrivate::handleProviderData(QNetworkReply *reply)
255 if ( reply->operation() == QNetworkAccessManager::HeadOperation ) {
256 const QVariant redirectionAttribute = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
257 if ( !redirectionAttribute.isNull() ) {
258 for (
int i=0; i<m_items.size(); ++i ) {
259 NewstuffItem &item = m_items[i];
260 if ( item.m_payloadUrl == reply->url() ) {
261 item.m_payloadUrl = redirectionAttribute.toUrl();
264 m_networkAccessManager.head( QNetworkRequest( redirectionAttribute.toUrl() ) );
268 QVariant
const size = reply->header( QNetworkRequest::ContentLengthHeader );
269 if ( size.isValid() ) {
270 qint64 length = size.value<qint64>();
271 for (
int i=0; i<m_items.size(); ++i ) {
272 NewstuffItem &item = m_items[i];
273 if ( item.m_payloadUrl == reply->url() ) {
274 item.m_payloadSize = length;
275 QModelIndex
const affected = m_parent->index( i );
276 emit m_parent->dataChanged( affected, affected );
283 FetchPreviewJob *
const job = m_networkJobs.take( reply );
286 const QVariant redirectionAttribute = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
287 if ( !redirectionAttribute.isNull() ) {
288 QNetworkReply *redirectReply = m_networkAccessManager.get( QNetworkRequest( QUrl( redirectionAttribute.toUrl() ) ) );
290 m_networkJobs.insert( redirectReply, job );
296 job->run( reply->readAll() );
302 if ( !xml.setContent( reply->readAll() ) ) {
303 mDebug() <<
"Cannot parse newstuff xml data ";
309 QDomElement root = xml.documentElement();
310 QDomNodeList items = root.elementsByTagName(
"stuff" );
311 for (
unsigned int i = 0; i < items.length(); ++i ) {
312 m_items << importNode( items.item( i ) );
318 bool NewstuffModelPrivate::canExecute(
const QString &executable )
const
320 QString path = QProcessEnvironment::systemEnvironment().value(
"PATH",
"/usr/local/bin:/usr/bin:/bin" );
321 foreach(
const QString &dir, path.split( QLatin1Char(
':' ) ) ) {
322 QFileInfo application( QDir( dir ), executable );
323 if ( application.exists() ) {
331 void NewstuffModelPrivate::installMap()
333 if ( m_unpackProcess ) {
334 m_unpackProcess->close();
335 delete m_unpackProcess;
337 }
else if ( m_currentFile->fileName().endsWith( QLatin1String(
"tar.gz" ) ) && canExecute(
"tar" ) ) {
338 m_unpackProcess =
new QProcess;
339 QObject::connect( m_unpackProcess, SIGNAL(finished(
int)),
340 m_parent, SLOT(contentsListed(
int)) );
341 QStringList arguments = QStringList() <<
"-t" <<
"-z" <<
"-f" << m_currentFile->fileName();
342 m_unpackProcess->setWorkingDirectory( m_targetDirectory );
343 m_unpackProcess->start(
"tar", arguments );
345 if ( !m_currentFile->fileName().endsWith( QLatin1String(
"tar.gz" ) ) ) {
346 mDebug() <<
"Can only handle tar.gz files";
348 mDebug() <<
"Cannot extract archive: tar executable not found in PATH.";
353 void NewstuffModelPrivate::updateModel()
355 QDomNodeList items = m_root.elementsByTagName(
"stuff" );
356 for (
unsigned int i = 0; i < items.length(); ++i ) {
358 QDomNodeList matches = items.item( i ).toElement().elementsByTagName( key );
359 if ( matches.size() == 1 ) {
360 QString
const value = matches.at( 0 ).toElement().text();
362 for (
int j=0; j<m_items.size() && !found; ++j ) {
363 NewstuffItem &item = m_items[j];
365 item.m_registryNode = items.item( i );
369 item.m_registryNode = items.item( i );
376 NewstuffItem item = importNode( items.item( i ) );
378 item.m_registryNode = items.item( i );
380 item.m_registryNode = items.item( i );
387 m_parent->beginResetModel();
388 m_parent->endResetModel();
391 void NewstuffModelPrivate::saveRegistry()
393 QFile output( m_registryFile );
394 if ( !output.open( QFile::WriteOnly ) ) {
395 mDebug() <<
"Cannot open " << m_registryFile <<
" for writing";
397 QTextStream outStream( &output );
398 outStream << m_registryDocument.toString( 2 );
404 void NewstuffModelPrivate::uninstall(
int index )
408 QStringList directories;
409 QStringList
const files = m_items[index].installedFiles();
410 foreach(
const QString &file, files ) {
411 if ( file.endsWith(
'/' ) ) {
414 QFile::remove( file );
418 qSort( directories.begin(), directories.end(), NewstuffItem::deeperThan );
419 foreach(
const QString &dir, directories ) {
420 QDir::root().rmdir( dir );
423 m_items[index].m_registryNode.parentNode().removeChild( m_items[index].m_registryNode );
424 m_items[index].m_registryNode.clear();
428 void NewstuffModelPrivate::changeNode( QDomNode &node, QDomDocument &domDocument,
const QString &key,
const QString &value, NodeAction action )
430 if ( action == Append ) {
431 QDomNode newNode = node.appendChild( domDocument.createElement( key ) );
432 newNode.appendChild( domDocument.createTextNode( value ) );
434 QDomNode oldNode = node.namedItem( key );
435 if ( !oldNode.isNull() ) {
436 oldNode.removeChild( oldNode.firstChild() );
437 oldNode.appendChild( domDocument.createTextNode( value ) );
443 void NewstuffModelPrivate::readValue(
const QDomNode &node,
const QString &key, T* target )
const
445 QDomNodeList matches = node.toElement().elementsByTagName( key );
446 if ( matches.size() == 1 ) {
447 *target = matches.at( 0 ).toElement().text();
449 for (
int i=0; i<matches.size(); ++i ) {
450 if ( matches.at( i ).attributes().contains(
"lang" ) &&
451 matches.at( i ).attributes().namedItem(
"lang").toAttr().value() ==
"en" ) {
452 *target = matches.at( i ).toElement().text();
460 QAbstractListModel( parent ), d( new NewstuffModelPrivate( this ) )
465 connect( &d->m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
466 this, SLOT(handleProviderData(QNetworkReply*)) );
468 QHash<int,QByteArray> roles;
469 roles[Qt::DisplayRole] =
"display";
470 roles[
Name] =
"name";
487 #if QT_VERSION < 0x050000
488 setRoleNames( roles );
490 d->m_roleNames = roles;
501 if ( !parent.isValid() ) {
502 return d->m_items.size();
510 if ( index.isValid() && index.row() >= 0 && index.row() < d->m_items.size() ) {
512 case Qt::DisplayRole:
return d->m_items.at( index.row() ).m_name;
513 case Qt::DecorationRole:
return d->preview( index.row() );
514 case Name:
return d->m_items.at( index.row() ).m_name;
515 case Author:
return d->m_items.at( index.row() ).m_author;
516 case License:
return d->m_items.at( index.row() ).m_license;
517 case Summary:
return d->m_items.at( index.row() ).m_summary;
518 case Version:
return d->m_items.at( index.row() ).m_version;
519 case ReleaseDate:
return d->m_items.at( index.row() ).m_releaseDate;
520 case Preview:
return d->m_items.at( index.row() ).m_previewUrl;
521 case Payload:
return d->m_items.at( index.row() ).m_payloadUrl;
522 case InstalledVersion:
return d->m_items.at( index.row() ).installedVersion();
524 case InstalledFiles:
return d->m_items.at( index.row() ).installedFiles();
525 case IsInstalled:
return !d->m_items.at( index.row() ).m_registryNode.isNull();
526 case IsUpgradable:
return d->m_items.at( index.row() ).isUpgradable();
527 case Category:
return d->m_items.at( index.row() ).m_category;
530 qint64
const size = d->m_items.at( index.row() ).m_payloadSize;
531 QUrl
const url = d->m_items.at( index.row() ).m_payloadUrl;
532 if ( size < -1 && !url.isEmpty() ) {
533 d->m_items[index.row()].m_payloadSize = -1;
534 d->m_networkAccessManager.head( QNetworkRequest( url ) );
537 return qMax<qint64>( -1, size );
539 case DownloadedSize:
return d->m_items.at( index.row() ).m_downloadedSize;
546 #if QT_VERSION >= 0x050000
547 QHash<int, QByteArray> NewstuffModel::roleNames()
const
549 return d->m_roleNames;
561 if ( downloadUrl == d->m_provider ) {
565 d->m_provider = downloadUrl;
567 d->m_networkAccessManager.get( QNetworkRequest( QUrl( downloadUrl ) ) );
572 return d->m_provider;
577 if ( targetDirectory != d->m_targetDirectory ) {
578 QFileInfo targetDir( targetDirectory );
579 if ( !targetDir.exists() ) {
580 if ( !QDir::root().mkpath( targetDir.absoluteFilePath() ) ) {
581 qDebug() <<
"Failed to create directory " << targetDirectory <<
", newstuff installation might fail.";
592 return d->m_targetDirectory;
598 if ( registryFile.startsWith(
'~' ) && registryFile.length() > 1 ) {
599 registryFile = QDir::homePath() + registryFile.mid( 1 );
602 if ( d->m_registryFile != registryFile ) {
607 QFileInfo inputFile( registryFile );
608 if ( !inputFile.exists() ) {
609 QDir::root().mkpath( inputFile.absolutePath() );
610 d->m_registryDocument = QDomDocument(
"khotnewstuff3" );
611 QDomProcessingInstruction header = d->m_registryDocument.createProcessingInstruction(
"xml",
"version=\"1.0\" encoding=\"utf-8\"" );
612 d->m_registryDocument.appendChild( header );
613 d->m_root = d->m_registryDocument.createElement(
"hotnewstuffregistry" );
614 d->m_registryDocument.appendChild( d->m_root );
616 QFile input( registryFile );
617 if ( !input.open( QFile::ReadOnly ) ) {
622 if ( !d->m_registryDocument.setContent( &input ) ) {
627 d->m_root = d->m_registryDocument.documentElement();
636 return d->m_registryFile;
641 if ( index < 0 || index >= d->m_items.size() ) {
645 NewstuffModelPrivate::Action action( index, NewstuffModelPrivate::Install );
647 QMutexLocker locker( &d->m_mutex );
648 if ( d->m_actionQueue.contains( action ) ) {
651 d->m_actionQueue << action;
659 if ( idx < 0 || idx >= d->m_items.size() ) {
663 if ( d->m_items[idx].m_registryNode.isNull() ) {
667 NewstuffModelPrivate::Action action( idx, NewstuffModelPrivate::Uninstall );
669 QMutexLocker locker( &d->m_mutex );
670 if ( d->m_actionQueue.contains( action ) ) {
673 d->m_actionQueue << action;
681 if ( !d->isTransitioning( index ) ) {
686 QMutexLocker locker( &d->m_mutex );
687 if ( d->m_currentAction.first == index ) {
688 if ( d->m_currentAction.second == NewstuffModelPrivate::Install ) {
689 if ( d->m_currentReply ) {
690 d->m_currentReply->abort();
691 d->m_currentReply->deleteLater();
692 d->m_currentReply = 0;
695 if ( d->m_unpackProcess ) {
696 d->m_unpackProcess->terminate();
697 d->m_unpackProcess->deleteLater();
698 d->m_unpackProcess = 0;
701 if ( d->m_currentFile ) {
702 d->m_currentFile->deleteLater();
703 d->m_currentFile = 0;
706 d->m_items[d->m_currentAction.first].m_downloadedSize = 0;
708 emit
installationFailed( d->m_currentAction.first, tr(
"Installation aborted by user." ) );
709 d->m_currentAction = NewstuffModelPrivate::Action( -1, NewstuffModelPrivate::Install );
714 if ( d->m_currentAction.second == NewstuffModelPrivate::Install ) {
715 NewstuffModelPrivate::Action
install( index, NewstuffModelPrivate::Install );
716 d->m_actionQueue.removeAll( install );
719 NewstuffModelPrivate::Action
uninstall( index, NewstuffModelPrivate::Uninstall );
720 d->m_actionQueue.removeAll( uninstall );
729 void NewstuffModel::updateProgress( qint64 bytesReceived, qint64 bytesTotal )
731 qreal
const progress = qBound<qreal>( 0.0, 0.9 * bytesReceived / qreal( bytesTotal ), 1.0 );
733 NewstuffItem &item = d->m_items[d->m_currentAction.first];
734 item.m_payloadSize = bytesTotal;
735 if ( qreal(bytesReceived-item.m_downloadedSize)/bytesTotal >= 0.01 || progress >= 0.9 ) {
737 item.m_downloadedSize = bytesReceived;
738 QModelIndex
const affected = index( d->m_currentAction.first );
739 emit dataChanged( affected, affected );
743 void NewstuffModel::retrieveData()
745 if ( d->m_currentReply && d->m_currentReply->isReadable() ) {
747 const QVariant redirectionAttribute = d->m_currentReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
748 if ( !redirectionAttribute.isNull() ) {
749 d->m_currentReply = d->m_networkAccessManager.get( QNetworkRequest( redirectionAttribute.toUrl() ) );
750 QObject::connect( d->m_currentReply, SIGNAL(readyRead()),
this, SLOT(retrieveData()) );
751 QObject::connect( d->m_currentReply, SIGNAL(readChannelFinished()),
this, SLOT(retrieveData()) );
752 QObject::connect( d->m_currentReply, SIGNAL(downloadProgress(qint64,qint64)),
753 this, SLOT(updateProgress(qint64,qint64)) );
755 d->m_currentFile->write( d->m_currentReply->readAll() );
756 if ( d->m_currentReply->isFinished() ) {
757 d->m_currentReply->deleteLater();
758 d->m_currentReply = 0;
759 d->m_currentFile->flush();
766 void NewstuffModel::mapInstalled(
int exitStatus )
768 if ( d->m_unpackProcess ) {
769 d->m_unpackProcess->deleteLater();
770 d->m_unpackProcess = 0;
773 if ( d->m_currentFile ) {
774 d->m_currentFile->deleteLater();
775 d->m_currentFile = 0;
779 d->m_items[d->m_currentAction.first].m_downloadedSize = 0;
780 if ( exitStatus == 0 ) {
783 mDebug() <<
"Process exit status " << exitStatus <<
" indicates an error.";
784 emit
installationFailed( d->m_currentAction.first , QString(
"Unable to unpack file. Process exited with status code %1." ).arg( exitStatus ) );
786 QModelIndex
const affected = index( d->m_currentAction.first );
789 QMutexLocker locker( &d->m_mutex );
790 d->m_currentAction = NewstuffModelPrivate::Action( -1, NewstuffModelPrivate::Install );
792 emit dataChanged( affected, affected );
796 void NewstuffModel::mapUninstalled()
798 QModelIndex
const affected = index( d->m_currentAction.first );
802 QMutexLocker locker( &d->m_mutex );
803 d->m_currentAction = NewstuffModelPrivate::Action( -1, NewstuffModelPrivate::Install );
805 emit dataChanged( affected, affected );
809 void NewstuffModel::contentsListed(
int exitStatus )
812 if ( exitStatus == 0 ) {
813 if ( !d->m_registryFile.isEmpty() ) {
814 NewstuffItem &item = d->m_items[d->m_currentAction.first];
815 QDomNode node = item.m_registryNode;
816 NewstuffModelPrivate::NodeAction action = node.isNull() ? NewstuffModelPrivate::Append : NewstuffModelPrivate::Replace;
817 if ( node.isNull() ) {
818 node = d->m_root.appendChild( d->m_registryDocument.createElement(
"stuff" ) );
821 node.toElement().setAttribute(
"category", d->m_items[d->m_currentAction.first].m_category );
822 d->changeNode( node, d->m_registryDocument,
"name", item.m_name, action );
823 d->changeNode( node, d->m_registryDocument,
"providerid", d->m_provider, action );
824 d->changeNode( node, d->m_registryDocument,
"author", item.m_author, action );
825 d->changeNode( node, d->m_registryDocument,
"homepage", QString(), action );
826 d->changeNode( node, d->m_registryDocument,
"licence", item.m_license, action );
827 d->changeNode( node, d->m_registryDocument,
"version", item.m_version, action );
828 QString
const itemId = d->m_idTag ==
PayloadTag ? item.m_payloadUrl.toString() : item.m_name;
829 d->changeNode( node, d->m_registryDocument,
"id", itemId, action );
830 d->changeNode( node, d->m_registryDocument,
"releasedate", item.m_releaseDate, action );
831 d->changeNode( node, d->m_registryDocument,
"summary", item.m_summary, action );
832 d->changeNode( node, d->m_registryDocument,
"changelog", QString(), action );
833 d->changeNode( node, d->m_registryDocument,
"preview", item.m_previewUrl.toString(), action );
834 d->changeNode( node, d->m_registryDocument,
"previewBig", item.m_previewUrl.toString(), action );
835 d->changeNode( node, d->m_registryDocument,
"payload", item.m_payloadUrl.toString(), action );
836 d->changeNode( node, d->m_registryDocument,
"status",
"installed", action );
837 d->m_items[d->m_currentAction.first].m_registryNode = node;
839 bool hasChildren =
true;
840 while ( hasChildren ) {
842 QDomNodeList fileList = node.toElement().elementsByTagName(
"installedfile" );
843 hasChildren = !fileList.isEmpty();
844 for (
int i=0; i<fileList.count(); ++i ) {
845 node.removeChild( fileList.at( i ) );
849 QStringList
const files = QString( d->m_unpackProcess->readAllStandardOutput() ).split(
'\n', QString::SkipEmptyParts );
850 foreach(
const QString &file, files ) {
851 QDomNode fileNode = node.appendChild( d->m_registryDocument.createElement(
"installedfile" ) );
852 fileNode.appendChild( d->m_registryDocument.createTextNode( d->m_targetDirectory +
'/' + file ) );
858 QObject::disconnect( d->m_unpackProcess, SIGNAL(finished(
int)),
859 this, SLOT(contentsListed(
int)) );
860 QObject::connect( d->m_unpackProcess, SIGNAL(finished(
int)),
861 this, SLOT(mapInstalled(
int)) );
862 QStringList arguments = QStringList() <<
"-x" <<
"-z" <<
"-f" << d->m_currentFile->fileName();
863 d->m_unpackProcess->start(
"tar", arguments );
865 mDebug() <<
"Process exit status " << exitStatus <<
" indicates an error.";
866 emit
installationFailed( d->m_currentAction.first , QString(
"Unable to list file contents. Process exited with status code %1." ).arg( exitStatus ) );
869 QMutexLocker locker( &d->m_mutex );
870 d->m_currentAction = NewstuffModelPrivate::Action( -1, NewstuffModelPrivate::Install );
876 void NewstuffModelPrivate::processQueue()
878 if ( m_actionQueue.empty() || m_currentAction.first >= 0 ) {
883 QMutexLocker locker( &m_mutex );
884 m_currentAction = m_actionQueue.takeFirst();
886 if ( m_currentAction.second == Install ) {
887 if ( !m_currentFile ) {
888 QFileInfo
const file = m_items.at( m_currentAction.first ).m_payloadUrl.path();
889 m_currentFile =
new QTemporaryFile( QDir::tempPath() +
"/marble-XXXXXX-" + file.fileName() );
892 if ( m_currentFile->open() ) {
893 QUrl
const payload = m_items.at( m_currentAction.first ).m_payloadUrl;
894 m_currentReply = m_networkAccessManager.get( QNetworkRequest( payload ) );
895 QObject::connect( m_currentReply, SIGNAL(readyRead()), m_parent, SLOT(retrieveData()) );
896 QObject::connect( m_currentReply, SIGNAL(readChannelFinished()), m_parent, SLOT(retrieveData()) );
897 QObject::connect( m_currentReply, SIGNAL(downloadProgress(qint64,qint64)),
898 m_parent, SLOT(updateProgress(qint64,qint64)) );
901 mDebug() <<
"Failed to write to " << m_currentFile->fileName();
905 QFutureWatcher<void>* watcher =
new QFutureWatcher<void>( m_parent );
906 QObject::connect( watcher, SIGNAL(finished()), m_parent, SLOT(mapUninstalled()) );
907 QObject::connect( watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()) );
909 QFuture<void> future = QtConcurrent::run(
this, &NewstuffModelPrivate::uninstall, m_currentAction.first );
910 watcher->setFuture( future );
914 NewstuffItem NewstuffModelPrivate::importNode(
const QDomNode &node)
const
917 item.m_category = node.attributes().namedItem(
"category" ).toAttr().value();
918 readValue<QString>( node,
"name", &item.m_name );
919 readValue<QString>( node,
"author", &item.m_author );
920 readValue<QString>( node,
"licence", &item.m_license );
921 readValue<QString>( node,
"summary", &item.m_summary );
922 readValue<QString>( node,
"version", &item.m_version );
923 readValue<QString>( node,
"releasedate", &item.m_releaseDate );
924 readValue<QUrl>( node,
"preview", &item.m_previewUrl );
925 readValue<QUrl>( node,
"payload", &item.m_payloadUrl );
929 bool NewstuffModelPrivate::isTransitioning(
int index )
const
931 if ( m_currentAction.first == index ) {
935 foreach(
const Action &action, m_actionQueue ) {
936 if ( action.first == index ) {
946 #include "NewstuffModel.moc"
void installationProgressed(int newstuffindex, qreal progress)
void targetDirectoryChanged()
void setProvider(const QString &downloadUrl)
Add a newstuff provider.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Overload of QAbstractListModel.
static QString localPath()
void installationFinished(int newstuffindex)
NewstuffModel(QObject *parent=0)
Constructor.
void setTargetDirectory(const QString &targetDirectory)
void installationFailed(int newstuffindex, const QString &error)
void uninstall(int index)
void setRegistryFile(const QString ®istryFile, IdTag idTag=PayloadTag)
int rowCount(const QModelIndex &parent=QModelIndex()) const
Overload of QAbstractListModel.
~NewstuffModel()
Destructor.
The class that displays copyright info.
QDebug mDebug()
a function to replace qDebug() in Marble library code
QString targetDirectory() const
QString registryFile() const
void registryFileChanged()
void uninstallationFinished(int newstuffindex)