20 #include <QSignalMapper>
21 #include <QStringListModel>
23 #include <QPushButton>
25 #include <QSortFilterProxyModel>
26 #include <QMessageBox>
27 #include <QNetworkAccessManager>
28 #include <QNetworkReply>
29 #include <QDomDocument>
37 void setPayload(
const QString &payload );
41 void setName(
const QString &name );
69 class MonavConfigWidgetPrivate
72 MonavConfigWidget* m_parent;
74 MonavPlugin* m_plugin;
84 MonavMapsModel* m_mapsModel;
102 MonavConfigWidgetPrivate( MonavConfigWidget* parent, MonavPlugin* plugin );
106 bool updateContinents(
QComboBox* comboBox );
118 void updateInstalledMapsView();
120 void updateInstalledMapsViewButtons();
122 void updateTransportPreference();
124 static bool canExecute(
const QString &executable );
126 void setBusy(
bool busy,
const QString &message =
QString() )
const;
132 void MonavStuffEntry::setPayload(
const QString &payload )
137 QString MonavStuffEntry::payload()
const
142 void MonavStuffEntry::setName(
const QString &name )
146 int size = parsed.
size();
147 m_continent = size > 0 ? parsed.
at( 0 ).trimmed() :
QString();
148 m_state = size > 1 ? parsed.
at( 1 ).trimmed() :
QString();
149 m_region = size > 2 ? parsed.
at( 2 ).trimmed() :
QString();
150 m_transport =
"Motorcar";
154 QRegExp regexp(
"([^(]+)\\(([^)]+)\\)");
155 if ( regexp.indexIn( last ) >= 0 ) {
157 if ( matches.
size() == 3 ) {
158 m_transport = matches.
at( 2 ).trimmed();
160 m_region = matches.
at( 1 ).trimmed();
162 m_state = matches.
at( 1 ).trimmed();
169 QString MonavStuffEntry::name()
const
174 QString MonavStuffEntry::continent()
const
179 QString MonavStuffEntry::state()
const
184 QString MonavStuffEntry::region()
const
189 QString MonavStuffEntry::transport()
const
194 bool MonavStuffEntry::isValid()
const
196 return !m_continent.
isEmpty() && !m_state.isEmpty() && m_payload.startsWith(
QLatin1String(
"http://" ) );
199 MonavConfigWidgetPrivate::MonavConfigWidgetPrivate( MonavConfigWidget* parent, MonavPlugin* plugin ) :
200 m_parent( parent ), m_plugin( plugin ), m_networkAccessManager( 0 ),
202 m_mapsModel( 0 ), m_initialized( false )
204 m_filteredModel->setFilterKeyColumn( 1 );
207 void MonavConfigWidgetPrivate::parseNewStuff(
const QByteArray &data )
211 mDebug() <<
"Cannot parse xml file " << data;
217 #if QT_VERSION < 0x050000
222 for ( ; i < items.
length(); ++i ) {
223 MonavStuffEntry item;
227 if ( names.
size() == 1 ) {
233 if ( dates.
size() == 1 ) {
239 if ( payloads.
size() == 1 ) {
242 item.setPayload( payload );
245 if ( item.isValid() ) {
246 m_remoteMaps.push_back( item );
248 m_remoteVersions[filename] = releaseDate;
253 m_mapsModel->setInstallableVersions( m_remoteVersions );
254 updateInstalledMapsViewButtons();
265 bool MonavConfigWidgetPrivate::updateContinents(
QComboBox* comboBox )
268 foreach(
const MonavStuffEntry &map, m_remoteMaps ) {
269 Q_ASSERT( map.isValid() );
270 continents << map.continent();
273 return fillComboBox( continents.
toList(), comboBox );
276 bool MonavConfigWidgetPrivate::updateStates(
const QString &continent,
QComboBox* comboBox )
279 foreach(
const MonavStuffEntry &map, m_remoteMaps ) {
280 Q_ASSERT( map.isValid() );
281 if ( map.continent() == continent ) {
282 states << map.state();
286 return fillComboBox( states.
toList(), comboBox );
289 bool MonavConfigWidgetPrivate::updateRegions(
const QString &continent,
const QString &state,
QComboBox* comboBox )
293 foreach(
const MonavStuffEntry &map, m_remoteMaps ) {
294 Q_ASSERT( map.isValid() );
295 if ( map.continent() == continent && map.state() == state ) {
297 if ( map.region().isEmpty() ) {
298 item = item.
arg( map.state() );
299 comboBox->
addItem( item.
arg( map.transport() ), map.payload() );
301 item = item.
arg( map.region(), map.transport() );
302 regions.
insert( item, map.payload() );
308 while ( iter.hasNext() ) {
310 comboBox->
addItem( iter.key(), iter.value() );
316 MonavStuffEntry MonavConfigWidgetPrivate::map(
const QString &continent,
const QString &state,
const QString ®ion )
const
318 foreach(
const MonavStuffEntry &entry, m_remoteMaps ) {
319 if ( continent == entry.continent() && state == entry.state() && region == entry.region() ) {
324 return MonavStuffEntry();
328 d( new MonavConfigWidgetPrivate( this, plugin ) )
332 m_statusLabel->setHidden( m_statusLabel->text().isEmpty() );
334 m_installedMapsListView->setModel( d->m_mapsModel );
335 m_configureMapsListView->setModel( d->m_filteredModel );
336 m_configureMapsListView->resizeColumnsToContents();
340 connect( m_continentComboBox, SIGNAL(currentIndexChanged(
int)),
341 this, SLOT(updateStates()) );
342 connect( m_transportTypeComboBox, SIGNAL(currentIndexChanged(
QString)),
343 this, SLOT(updateTransportTypeFilter(
QString)) );
344 connect( m_stateComboBox, SIGNAL(currentIndexChanged(
int)),
345 this, SLOT(updateRegions()) );
346 connect( m_installButton, SIGNAL(clicked()),
this, SLOT(downloadMap()) );
347 connect( m_cancelButton, SIGNAL(clicked()),
this, SLOT(cancelOperation()) );
348 connect( &d->m_removeMapSignalMapper, SIGNAL(mapped(
int)),
349 this, SLOT(removeMap(
int)) );
350 connect( &d->m_upgradeMapSignalMapper, SIGNAL(mapped(
int)),
351 this, SLOT(upgradeMap(
int)) );
363 d->m_transport = settings[
"transport"].toString();
364 d->updateTransportPreference();
367 void MonavConfigWidgetPrivate::updateTransportPreference()
369 if ( m_parent->m_transportTypeComboBox && m_mapsModel ) {
370 m_parent->m_transportTypeComboBox->blockSignals(
true );
371 m_parent->m_transportTypeComboBox->clear();
373 for(
int i=0; i<m_mapsModel->rowCount(); ++i ) {
375 transportTypes << m_mapsModel->data( index ).toString();
377 m_parent->m_transportTypeComboBox->addItems( transportTypes.
toList() );
378 m_parent->m_transportTypeComboBox->blockSignals(
false );
380 if ( !m_transport.isEmpty() && m_parent->m_transportTypeComboBox ) {
381 for (
int i=1; i<m_parent->m_transportTypeComboBox->count(); ++i ) {
382 if ( m_parent->m_transportTypeComboBox->itemText( i ) == m_transport ) {
383 m_parent->m_transportTypeComboBox->setCurrentIndex( i );
394 settings[
"transport"] = d->m_transport;
398 void MonavConfigWidget::retrieveMapList(
QNetworkReply *reply )
400 if ( reply->
isReadable() && d->m_currentDownload.isEmpty() ) {
402 QVariant const redirectionAttribute = reply->
attribute( QNetworkRequest::RedirectionTargetAttribute );
403 if ( !redirectionAttribute.
isNull() ) {
408 d->parseNewStuff( reply->
readAll() );
414 void MonavConfigWidget::retrieveData()
416 if ( d->m_currentReply && d->m_currentReply->isReadable() && !d->m_currentDownload.isEmpty() ) {
418 QVariant const redirectionAttribute = d->m_currentReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
419 if ( !redirectionAttribute.
isNull() ) {
420 d->m_currentReply = d->m_networkAccessManager.get(
QNetworkRequest( redirectionAttribute.
toUrl() ) );
421 connect( d->m_currentReply, SIGNAL(readyRead()),
422 this, SLOT(retrieveData()) );
423 connect( d->m_currentReply, SIGNAL(readChannelFinished()),
424 this, SLOT(retrieveData()) );
425 connect( d->m_currentReply, SIGNAL(downloadProgress(qint64,qint64)),
426 this, SLOT(updateProgressBar(qint64,qint64)) );
428 d->m_currentFile.write( d->m_currentReply->readAll() );
429 if ( d->m_currentReply->isFinished() ) {
430 d->m_currentReply->deleteLater();
431 d->m_currentReply = 0;
432 d->m_currentFile.close();
434 d->m_currentDownload.clear();
440 void MonavConfigWidget::updateComboBoxes()
442 d->updateContinents( m_continentComboBox );
447 void MonavConfigWidget::updateStates()
449 bool const haveContinents = m_continentComboBox->currentIndex() >= 0;
450 if ( haveContinents ) {
451 QString const continent = m_continentComboBox->currentText();
452 if ( d->updateStates( continent, m_stateComboBox ) ) {
458 void MonavConfigWidget::updateRegions()
460 bool haveRegions =
false;
461 if ( m_continentComboBox->currentIndex() >= 0 ) {
462 if ( m_stateComboBox->currentIndex() >= 0 ) {
463 QString const continent = m_continentComboBox->currentText();
464 QString const state = m_stateComboBox->currentText();
465 haveRegions = d->updateRegions( continent, state, m_regionComboBox );
469 m_regionLabel->setVisible( haveRegions );
470 m_regionComboBox->setVisible( haveRegions );
473 void MonavConfigWidget::downloadMap()
475 if ( d->m_currentDownload.isEmpty() && !d->m_currentFile.isOpen() ) {
476 d->m_currentDownload = m_regionComboBox->itemData( m_regionComboBox->currentIndex() ).
toString();
481 void MonavConfigWidget::cancelOperation()
483 if ( !d->m_currentDownload.isEmpty() || d->m_currentFile.isOpen() ) {
484 d->m_currentReply->abort();
485 d->m_currentReply->deleteLater();
486 d->m_currentReply = 0;
487 d->m_currentDownload.clear();
489 d->m_currentFile.close();
493 void MonavConfigWidgetPrivate::install()
495 if ( !m_currentDownload.isEmpty() ) {
496 int const index = m_currentDownload.lastIndexOf(
"/");
498 m_currentFile.setFileName( localFile );
499 if ( m_currentFile.open( QFile::WriteOnly ) ) {
502 setBusy(
true, message );
503 m_currentReply = m_networkAccessManager.get(
QNetworkRequest( m_currentDownload ) );
505 m_parent, SLOT(retrieveData()) );
507 m_parent, SLOT(retrieveData()) );
509 m_parent, SLOT(updateProgressBar(qint64,qint64)) );
511 mDebug() <<
"Failed to write to " << localFile;
516 void MonavConfigWidgetPrivate::installMap()
518 if ( m_unpackProcess ) {
519 m_unpackProcess->close();
520 delete m_unpackProcess;
522 m_parent->m_installButton->setEnabled(
true );
523 }
else if ( m_currentFile.fileName().endsWith(
QLatin1String(
"tar.gz" ) ) && canExecute(
"tar" ) ) {
526 setBusy(
true, message );
527 m_parent->m_progressBar->setMaximum( 0 );
528 if ( file.exists() && file.isReadable() ) {
531 m_parent, SLOT(mapInstalled(
int)) );
533 m_unpackProcess->setWorkingDirectory( file.dir().absolutePath() );
534 m_unpackProcess->start(
"tar", arguments );
537 if ( !m_currentFile.fileName().endsWith(
QLatin1String(
"tar.gz" ) ) ) {
538 mDebug() <<
"Can only handle tar.gz files";
540 mDebug() <<
"Cannot extract archive: tar executable not found in PATH.";
545 void MonavConfigWidget::updateProgressBar( qint64 bytesReceived, qint64 bytesTotal )
549 m_progressBar->setMaximum( bytesTotal / 1024 );
550 m_progressBar->setValue( bytesReceived / 1024 );
552 m_progressBar->setFormat( progress.
arg( bytesReceived / 1024 / 1024 ).
arg( bytesTotal / 1024 / 1024 ) );
555 bool MonavConfigWidgetPrivate::canExecute(
const QString &executable )
560 if ( application.exists() ) {
568 void MonavConfigWidget::mapInstalled(
int exitStatus )
570 d->m_unpackProcess = 0;
571 d->m_currentFile.remove();
574 if ( exitStatus == 0 ) {
575 d->m_plugin->reloadMaps();
576 d->updateInstalledMapsView();
577 monavTabWidget->setCurrentIndex( 0 );
579 mDebug() <<
"Error when unpacking archive, process exited with status code " << exitStatus;
587 if ( !event->
spontaneous() && !d->m_initialized ) {
588 d->m_initialized =
true;
589 d->updateInstalledMapsView();
590 QUrl url =
QUrl(
"http://files.kde.org/marble/newstuff/maps-monav.xml" );
595 void MonavConfigWidgetPrivate::updateInstalledMapsView()
597 m_mapsModel = m_plugin->installedMapsModel();
598 m_mapsModel->setInstallableVersions( m_remoteVersions );
599 m_filteredModel->setSourceModel( m_mapsModel );
600 m_parent->m_installedMapsListView->setModel( m_mapsModel );
602 m_parent->m_configureMapsListView->setColumnHidden( 1,
true );
603 m_parent->m_installedMapsListView->setColumnHidden( 2,
true );
604 m_parent->m_configureMapsListView->setColumnHidden( 3,
true );
605 m_parent->m_configureMapsListView->setColumnHidden( 4,
true );
606 m_parent->m_installedMapsListView->setColumnHidden( 5,
true );
608 m_parent->m_configureMapsListView->horizontalHeader()->setVisible(
true );
609 m_parent->m_installedMapsListView->horizontalHeader()->setVisible(
true );
610 m_parent->m_configureMapsListView->resizeColumnsToContents();
611 m_parent->m_installedMapsListView->resizeColumnsToContents();
613 updateTransportPreference();
614 updateInstalledMapsViewButtons();
617 void MonavConfigWidgetPrivate::updateInstalledMapsViewButtons()
619 m_removeMapSignalMapper.removeMappings( m_parent );
620 m_upgradeMapSignalMapper.removeMappings( m_parent );
621 for(
int i=0; i<m_mapsModel->rowCount(); ++i ) {
626 m_parent->m_installedMapsListView->setIndexWidget( index, button );
627 m_upgradeMapSignalMapper.setMapping( button, index.
row() );
628 QObject::connect( button, SIGNAL(clicked()), &m_upgradeMapSignalMapper, SLOT(map()) );
629 bool upgradable = m_mapsModel->data( index ).toBool();
630 QString canUpgradeText =
QObject::tr(
"An update is available. Click to install it." );
631 QString isLatestText =
QObject::tr(
"No update available. You are running the latest version." );
632 button->
setToolTip( upgradable ? canUpgradeText : isLatestText );
639 m_parent->m_installedMapsListView->setIndexWidget( index, button );
640 m_removeMapSignalMapper.setMapping( button, index.
row() );
641 QObject::connect( button, SIGNAL(clicked()), &m_removeMapSignalMapper, SLOT(map()) );
642 bool const writable = m_mapsModel->data( index ).toBool();
646 m_parent->m_installedMapsListView->resizeColumnsToContents();
649 void MonavConfigWidget::updateTransportTypeFilter(
const QString &filter )
651 d->m_filteredModel->setFilterFixedString( filter );
652 d->m_transport = filter;
653 m_configureMapsListView->resizeColumnsToContents();
656 void MonavConfigWidget::removeMap(
int index )
659 QString text =
tr(
"Are you sure you want to delete this map from the system?" );
661 d->m_mapsModel->deleteMapFiles( index );
662 d->m_plugin->reloadMaps();
663 d->updateInstalledMapsView();
667 void MonavConfigWidget::upgradeMap(
int index )
669 QString payload = d->m_mapsModel->payload( index );
671 foreach(
const MonavStuffEntry &entry, d->m_remoteMaps ) {
672 if ( entry.payload().endsWith(
'/' + payload ) ) {
673 d->m_currentDownload = entry.payload();
681 void MonavConfigWidgetPrivate::setBusy(
bool busy,
const QString &message )
const
684 m_parent->m_stackedWidget->removeWidget( m_parent->m_settingsPage );
685 m_parent->m_stackedWidget->addWidget( m_parent->m_progressPage );
687 m_parent->m_stackedWidget->removeWidget( m_parent->m_progressPage );
688 m_parent->m_stackedWidget->addWidget( m_parent->m_settingsPage );
692 m_parent->m_progressLabel->setText( message.
isEmpty() ? defaultMessage : message );
697 #include "MonavConfigWidget.moc"
QDomNodeList elementsByTagName(const QString &tagname) const
QDomNode item(int index) const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
static QString localPath()
QDomElement documentElement() const
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QString tr(const char *sourceText, const char *disambiguation, int n)
QString value(const QString &name, const QString &defaultValue) const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
void addItem(const QString &text, const QVariant &userData)
QDomElement toElement() const
StandardButton question(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
QFuture< void > map(Sequence &sequence, MapFunction function)
QString statusMessage() const
A status message showing whether the plugin will be able to deliver results.
QString mid(int position, int n) const
char * toString(const T &value)
QVariant attribute(QNetworkRequest::Attribute code) const
QList< T > toList() const
iterator insert(const Key &key, const T &value)
void addItems(const QStringList &texts)
QProcessEnvironment systemEnvironment()
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QDebug mDebug()
a function to replace qDebug() in Marble library code
QDomNode at(int index) const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)