File indexing completed on 2024-05-12 07:44:38

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "MonavConfigWidget.h"
0007 
0008 #include "MonavMapsModel.h"
0009 #include "MonavPlugin.h"
0010 #include "MarbleDirs.h"
0011 #include "MarbleDebug.h"
0012 
0013 #include <QFile>
0014 #include <QProcess>
0015 #include <QSignalMapper>
0016 #include <QPushButton>
0017 #include <QShowEvent>
0018 #include <QSortFilterProxyModel>
0019 #include <QMessageBox>
0020 #include <QNetworkAccessManager>
0021 #include <QNetworkReply>
0022 #include <QDomDocument>
0023 
0024 namespace Marble
0025 {
0026 
0027 class MonavStuffEntry
0028 {
0029 public:
0030     void setPayload( const QString &payload );
0031 
0032     QString payload() const;
0033 
0034     void setName( const QString &name );
0035 
0036     QString name() const;
0037 
0038     bool isValid() const;
0039 
0040     QString continent() const;
0041 
0042     QString state() const;
0043 
0044     QString region() const;
0045 
0046     QString transport() const;
0047 
0048 private:
0049     QString m_payload;
0050 
0051     QString m_name;
0052 
0053     QString m_continent;
0054 
0055     QString m_state;
0056 
0057     QString m_region;
0058 
0059     QString m_transport;
0060 };
0061 
0062 class MonavConfigWidgetPrivate
0063 {
0064 public:
0065     MonavConfigWidget* m_parent;
0066 
0067     MonavPlugin* m_plugin;
0068 
0069     QNetworkAccessManager m_networkAccessManager;
0070 
0071     QNetworkReply* m_currentReply;
0072 
0073     QProcess* m_unpackProcess;
0074 
0075     QSortFilterProxyModel* m_filteredModel;
0076 
0077     MonavMapsModel* m_mapsModel;
0078 
0079     bool m_initialized;
0080 
0081     QSignalMapper m_removeMapSignalMapper;
0082 
0083     QSignalMapper m_upgradeMapSignalMapper;
0084 
0085     QVector<MonavStuffEntry> m_remoteMaps;
0086 
0087     QMap<QString, QString> m_remoteVersions;
0088 
0089     QString m_currentDownload;
0090 
0091     QFile m_currentFile;
0092 
0093     QString m_transport;
0094 
0095     MonavConfigWidgetPrivate( MonavConfigWidget* parent, MonavPlugin* plugin );
0096 
0097     void parseNewStuff( const QByteArray &data );
0098 
0099     bool updateContinents( QComboBox* comboBox );
0100 
0101     bool updateStates( const QString &continent, QComboBox* comboBox );
0102 
0103     bool updateRegions( const QString &continent, const QString &state, QComboBox* comboBox );
0104 
0105     MonavStuffEntry map( const QString &continent, const QString &state, const QString &region ) const;
0106 
0107     void install();
0108 
0109     void installMap();
0110 
0111     void updateInstalledMapsView();
0112 
0113     void updateInstalledMapsViewButtons();
0114 
0115     void updateTransportPreference();
0116 
0117     static bool canExecute( const QString &executable );
0118 
0119     void setBusy( bool busy, const QString &message = QString() ) const;
0120 
0121 private:
0122     static bool fillComboBox( QStringList items, QComboBox* comboBox );
0123 };
0124 
0125 void MonavStuffEntry::setPayload( const QString &payload )
0126 {
0127     m_payload = payload;
0128 }
0129 
0130 QString MonavStuffEntry::payload() const
0131 {
0132     return m_payload;
0133 }
0134 
0135 void MonavStuffEntry::setName( const QString &name )
0136 {
0137     m_name = name;
0138     QStringList parsed = name.split( QLatin1Char( '/' ) );
0139     int size = parsed.size();
0140     m_continent = size > 0 ? parsed.at( 0 ).trimmed() : QString();
0141     m_state = size > 1 ? parsed.at( 1 ).trimmed() : QString();
0142     m_region = size > 2 ? parsed.at( 2 ).trimmed() : QString();
0143     m_transport = "Motorcar"; // No i18n
0144 
0145     if ( size > 1 ) {
0146         QString last = parsed.last().trimmed();
0147         QRegExp regexp("([^(]+)\\(([^)]+)\\)");
0148         if ( regexp.indexIn( last ) >= 0 ) {
0149             QStringList matches = regexp.capturedTexts();
0150             if ( matches.size() == 3 ) {
0151                 m_transport = matches.at( 2 ).trimmed();
0152                 if ( size > 2 ) {
0153                     m_region = matches.at( 1 ).trimmed();
0154                 } else {
0155                     m_state = matches.at( 1 ).trimmed();
0156                 }
0157             }
0158         }
0159     }
0160 }
0161 
0162 QString MonavStuffEntry::name() const
0163 {
0164     return m_name;
0165 }
0166 
0167 QString MonavStuffEntry::continent() const
0168 {
0169     return m_continent;
0170 }
0171 
0172 QString MonavStuffEntry::state() const
0173 {
0174     return m_state;
0175 }
0176 
0177 QString MonavStuffEntry::region() const
0178 {
0179     return m_region;
0180 }
0181 
0182 QString MonavStuffEntry::transport() const
0183 {
0184     return m_transport;
0185 }
0186 
0187 bool MonavStuffEntry::isValid() const
0188 {
0189     return !m_continent.isEmpty() && !m_state.isEmpty() && m_payload.startsWith( QLatin1String( "http://" ) );
0190 }
0191 
0192 MonavConfigWidgetPrivate::MonavConfigWidgetPrivate( MonavConfigWidget* parent, MonavPlugin* plugin ) :
0193         m_parent( parent ), m_plugin( plugin ), m_networkAccessManager( nullptr ),
0194         m_currentReply( nullptr ), m_unpackProcess( nullptr ), m_filteredModel( new QSortFilterProxyModel( parent) ),
0195         m_mapsModel( nullptr ), m_initialized( false )
0196 {
0197     m_filteredModel->setFilterKeyColumn( 1 );
0198 }
0199 
0200 void MonavConfigWidgetPrivate::parseNewStuff( const QByteArray &data )
0201 {
0202     QDomDocument xml;
0203     if ( !xml.setContent( data ) ) {
0204         mDebug() << "Cannot parse xml file " << data;
0205         return;
0206     }
0207 
0208     QDomElement root = xml.documentElement();
0209     QDomNodeList items = root.elementsByTagName(QStringLiteral("stuff"));
0210     for (int i=0 ; i < items.length(); ++i ) {
0211         MonavStuffEntry item;
0212         QDomNode node = items.item( i );
0213 
0214         QDomNodeList names = node.toElement().elementsByTagName(QStringLiteral("name"));
0215         if ( names.size() == 1 ) {
0216             item.setName( names.at( 0 ).toElement().text() );
0217         }
0218 
0219         QString releaseDate;
0220         QDomNodeList dates = node.toElement().elementsByTagName(QStringLiteral("releasedate"));
0221         if ( dates.size() == 1 ) {
0222             releaseDate = dates.at( 0 ).toElement().text();
0223         }
0224 
0225         QString filename;
0226         QDomNodeList payloads = node.toElement().elementsByTagName(QStringLiteral("payload"));
0227         if ( payloads.size() == 1 ) {
0228             QString payload = payloads.at( 0 ).toElement().text();
0229             filename = payload.mid(1 + payload.lastIndexOf(QLatin1Char('/')));
0230             item.setPayload( payload );
0231         }
0232 
0233         if ( item.isValid() ) {
0234             m_remoteMaps.push_back( item );
0235             if ( !filename.isEmpty() && !releaseDate.isEmpty() ) {
0236                 m_remoteVersions[filename] = releaseDate;
0237             }
0238         }
0239     }
0240 
0241     m_mapsModel->setInstallableVersions( m_remoteVersions );
0242     updateInstalledMapsViewButtons();
0243 }
0244 
0245 bool MonavConfigWidgetPrivate::fillComboBox( QStringList items, QComboBox* comboBox )
0246 {
0247     comboBox->clear();
0248     std::sort( items.begin(), items.end() );
0249     comboBox->addItems( items );
0250     return !items.isEmpty();
0251 }
0252 
0253 bool MonavConfigWidgetPrivate::updateContinents( QComboBox* comboBox )
0254 {
0255     QSet<QString> continents;
0256     for( const MonavStuffEntry &map: m_remoteMaps ) {
0257         Q_ASSERT( map.isValid() );
0258         continents << map.continent();
0259     }
0260 
0261     return fillComboBox( continents.values(), comboBox );
0262 }
0263 
0264 bool MonavConfigWidgetPrivate::updateStates( const QString &continent, QComboBox* comboBox )
0265 {
0266     QSet<QString> states;
0267     for( const MonavStuffEntry &map: m_remoteMaps ) {
0268         Q_ASSERT( map.isValid() );
0269         if ( map.continent() == continent ) {
0270             states << map.state();
0271         }
0272     }
0273 
0274     return fillComboBox( states.values(), comboBox );
0275 }
0276 
0277 bool MonavConfigWidgetPrivate::updateRegions( const QString &continent, const QString &state, QComboBox* comboBox )
0278 {
0279     comboBox->clear();
0280     QMap<QString,QString> regions;
0281     for( const MonavStuffEntry &map: m_remoteMaps ) {
0282         Q_ASSERT( map.isValid() );
0283         if ( map.continent() == continent && map.state() == state ) {
0284             QString item = "%1 - %2";
0285             if ( map.region().isEmpty() ) {
0286                 item = item.arg( map.state() );
0287                 comboBox->addItem( item.arg( map.transport() ), map.payload() );
0288             } else {
0289                 item = item.arg( map.region(), map.transport() );
0290                 regions.insert( item, map.payload() );
0291             }
0292         }
0293     }
0294 
0295     QMapIterator<QString, QString> iter( regions );
0296     while ( iter.hasNext() ) {
0297         iter.next();
0298         comboBox->addItem( iter.key(), iter.value() );
0299     }
0300 
0301     return true;
0302 }
0303 
0304 MonavStuffEntry MonavConfigWidgetPrivate::map( const QString &continent, const QString &state, const QString &region ) const
0305 {
0306     for( const MonavStuffEntry &entry: m_remoteMaps ) {
0307         if ( continent == entry.continent() && state == entry.state() && region == entry.region() ) {
0308             return entry;
0309         }
0310     }
0311 
0312     return MonavStuffEntry();
0313 }
0314 
0315 MonavConfigWidget::MonavConfigWidget( MonavPlugin* plugin ) :
0316         d( new MonavConfigWidgetPrivate( this, plugin ) )
0317 {
0318     setupUi( this );
0319     m_statusLabel->setText( plugin->statusMessage() );
0320     m_statusLabel->setHidden( m_statusLabel->text().isEmpty() );
0321     d->setBusy( false );
0322     m_installedMapsListView->setModel( d->m_mapsModel );
0323     m_configureMapsListView->setModel( d->m_filteredModel );
0324     m_configureMapsListView->resizeColumnsToContents();
0325 
0326     updateComboBoxes();
0327 
0328     connect( m_continentComboBox, SIGNAL(currentIndexChanged(int)),
0329              this, SLOT(updateStates()) );
0330     connect( m_transportTypeComboBox, SIGNAL(currentIndexChanged(QString)),
0331              this, SLOT(updateTransportTypeFilter(QString)) );
0332     connect( m_stateComboBox, SIGNAL(currentIndexChanged(int)),
0333              this, SLOT(updateRegions()) );
0334     connect( m_installButton, SIGNAL(clicked()), this, SLOT(downloadMap()) );
0335     connect( m_cancelButton, SIGNAL(clicked()), this, SLOT(cancelOperation()) );
0336     connect( &d->m_removeMapSignalMapper, SIGNAL(mapped(int)),
0337              this, SLOT(removeMap(int)) );
0338     connect( &d->m_upgradeMapSignalMapper, SIGNAL(mapped(int)),
0339              this, SLOT(upgradeMap(int)) );
0340     connect( &d->m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
0341              this, SLOT(retrieveMapList(QNetworkReply*)) );
0342 }
0343 
0344 MonavConfigWidget::~MonavConfigWidget()
0345 {
0346     delete d;
0347 }
0348 
0349 void MonavConfigWidget::loadSettings( const QHash<QString, QVariant> &settings )
0350 {
0351     d->m_transport = settings[QStringLiteral("transport")].toString();
0352     d->updateTransportPreference();
0353 }
0354 
0355 void MonavConfigWidgetPrivate::updateTransportPreference()
0356 {
0357     if ( m_parent->m_transportTypeComboBox && m_mapsModel ) {
0358         m_parent->m_transportTypeComboBox->blockSignals( true );
0359         m_parent->m_transportTypeComboBox->clear();
0360         QSet<QString> transportTypes;
0361         for( int i=0; i<m_mapsModel->rowCount(); ++i ) {
0362             QModelIndex index = m_mapsModel->index( i, 1 );
0363             transportTypes << m_mapsModel->data( index ).toString();
0364         }
0365         m_parent->m_transportTypeComboBox->addItems( transportTypes.values() );
0366         m_parent->m_transportTypeComboBox->blockSignals( false );
0367 
0368         if ( !m_transport.isEmpty() && m_parent->m_transportTypeComboBox ) {
0369             for ( int i=1; i<m_parent->m_transportTypeComboBox->count(); ++i ) {
0370                 if ( m_parent->m_transportTypeComboBox->itemText( i ) == m_transport ) {
0371                     m_parent->m_transportTypeComboBox->setCurrentIndex( i );
0372                     return;
0373                 }
0374             }
0375         }
0376     }
0377 }
0378 
0379 QHash<QString, QVariant> MonavConfigWidget::settings() const
0380 {
0381     QHash<QString, QVariant> settings;
0382     settings.insert(QStringLiteral("transport"), d->m_transport);
0383     return settings;
0384 }
0385 
0386 void MonavConfigWidget::retrieveMapList( QNetworkReply *reply )
0387 {
0388     if ( reply->isReadable() && d->m_currentDownload.isEmpty() ) {
0389         // check if we are redirected
0390         QVariant const redirectionAttribute = reply->attribute( QNetworkRequest::RedirectionTargetAttribute );
0391         if ( !redirectionAttribute.isNull() ) {
0392             d->m_networkAccessManager.get( QNetworkRequest( redirectionAttribute.toUrl() ) );
0393         } else {
0394             disconnect( &d->m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
0395                          this, SLOT(retrieveMapList(QNetworkReply*)) );
0396             d->parseNewStuff( reply->readAll() );
0397             updateComboBoxes();
0398         }
0399     }
0400 }
0401 
0402 void MonavConfigWidget::retrieveData()
0403 {
0404     if ( d->m_currentReply && d->m_currentReply->isReadable() && !d->m_currentDownload.isEmpty() ) {
0405         // check if we are redirected
0406         QVariant const redirectionAttribute = d->m_currentReply->attribute( QNetworkRequest::RedirectionTargetAttribute );
0407         if ( !redirectionAttribute.isNull() ) {
0408             d->m_currentReply = d->m_networkAccessManager.get( QNetworkRequest( redirectionAttribute.toUrl() ) );
0409             connect( d->m_currentReply, SIGNAL(readyRead()),
0410                          this, SLOT(retrieveData()) );
0411             connect( d->m_currentReply, SIGNAL(readChannelFinished()),
0412                          this, SLOT(retrieveData()) );
0413             connect( d->m_currentReply, SIGNAL(downloadProgress(qint64,qint64)),
0414                      this, SLOT(updateProgressBar(qint64,qint64)) );
0415         } else {
0416             d->m_currentFile.write( d->m_currentReply->readAll() );
0417             if ( d->m_currentReply->isFinished() ) {
0418                 d->m_currentReply->deleteLater();
0419                 d->m_currentReply = nullptr;
0420                 d->m_currentFile.close();
0421                 d->installMap();
0422                 d->m_currentDownload.clear();
0423             }
0424         }
0425     }
0426 }
0427 
0428 void MonavConfigWidget::updateComboBoxes()
0429 {
0430     d->updateContinents( m_continentComboBox );
0431     updateStates();
0432     updateRegions();
0433 }
0434 
0435 void MonavConfigWidget::updateStates()
0436 {
0437     bool const haveContinents = m_continentComboBox->currentIndex() >= 0;
0438     if ( haveContinents ) {
0439         QString const continent = m_continentComboBox->currentText();
0440         if ( d->updateStates( continent, m_stateComboBox ) ) {
0441             updateRegions();
0442         }
0443     }
0444 }
0445 
0446 void MonavConfigWidget::updateRegions()
0447 {
0448     bool haveRegions = false;
0449     if ( m_continentComboBox->currentIndex() >= 0 ) {
0450         if ( m_stateComboBox->currentIndex() >= 0 ) {
0451             QString const continent = m_continentComboBox->currentText();
0452             QString const state = m_stateComboBox->currentText();
0453             haveRegions = d->updateRegions( continent, state, m_regionComboBox );
0454         }
0455     }
0456 
0457     m_regionLabel->setVisible( haveRegions );
0458     m_regionComboBox->setVisible( haveRegions );
0459 }
0460 
0461 void MonavConfigWidget::downloadMap()
0462 {
0463     if ( d->m_currentDownload.isEmpty() && !d->m_currentFile.isOpen() ) {
0464         d->m_currentDownload = m_regionComboBox->itemData( m_regionComboBox->currentIndex() ).toString();
0465         d->install();
0466     }
0467 }
0468 
0469 void MonavConfigWidget::cancelOperation()
0470 {
0471     if ( !d->m_currentDownload.isEmpty() || d->m_currentFile.isOpen() ) {
0472         d->m_currentReply->abort();
0473         d->m_currentReply->deleteLater();
0474         d->m_currentReply = nullptr;
0475         d->m_currentDownload.clear();
0476         d->setBusy( false );
0477         d->m_currentFile.close();
0478     }
0479 }
0480 
0481 void MonavConfigWidgetPrivate::install()
0482 {
0483     if ( !m_currentDownload.isEmpty() ) {
0484         int const index = m_currentDownload.lastIndexOf(QLatin1Char('/'));
0485         const QString localFile = MarbleDirs::localPath() + QLatin1String("/maps") + m_currentDownload.mid(index);
0486         m_currentFile.setFileName( localFile );
0487         if ( m_currentFile.open( QFile::WriteOnly ) ) {
0488             QFileInfo file( m_currentFile );
0489             QString message = QObject::tr( "Downloading %1" ).arg( file.fileName() );
0490             setBusy( true, message );
0491             m_currentReply = m_networkAccessManager.get( QNetworkRequest( QUrl ( m_currentDownload ) ) );
0492             QObject::connect( m_currentReply, SIGNAL(readyRead()),
0493                          m_parent, SLOT(retrieveData()) );
0494             QObject::connect( m_currentReply, SIGNAL(readChannelFinished()),
0495                          m_parent, SLOT(retrieveData()) );
0496             QObject::connect( m_currentReply, SIGNAL(downloadProgress(qint64,qint64)),
0497                      m_parent, SLOT(updateProgressBar(qint64,qint64)) );
0498         } else {
0499             mDebug() << "Failed to write to " << localFile;
0500         }
0501     }
0502 }
0503 
0504 void MonavConfigWidgetPrivate::installMap()
0505 {
0506     if ( m_unpackProcess ) {
0507         m_unpackProcess->close();
0508         delete m_unpackProcess;
0509         m_unpackProcess = nullptr;
0510         m_parent->m_installButton->setEnabled( true );
0511     } else if ( m_currentFile.fileName().endsWith( QLatin1String( "tar.gz" ) ) && canExecute( "tar" ) ) {
0512         QFileInfo file( m_currentFile );
0513         QString message = QObject::tr( "Installing %1" ).arg( file.fileName() );
0514         setBusy( true, message );
0515         m_parent->m_progressBar->setMaximum( 0 );
0516         if ( file.exists() && file.isReadable() ) {
0517             m_unpackProcess = new QProcess;
0518             QObject::connect( m_unpackProcess, SIGNAL(finished(int)),
0519                      m_parent, SLOT(mapInstalled(int)) );
0520             QStringList arguments = QStringList() << "-x" << "-z" << "-f" << file.fileName();
0521             m_unpackProcess->setWorkingDirectory( file.dir().absolutePath() );
0522             m_unpackProcess->start( "tar", arguments );
0523         }
0524     } else {
0525         if ( !m_currentFile.fileName().endsWith( QLatin1String( "tar.gz" ) ) ) {
0526             mDebug() << "Can only handle tar.gz files";
0527         } else {
0528             mDebug() << "Cannot extract archive: tar executable not found in PATH.";
0529         }
0530     }
0531 }
0532 
0533 void MonavConfigWidget::updateProgressBar( qint64 bytesReceived, qint64 bytesTotal )
0534 {
0535     // Coarse MB resolution for the text to get it short,
0536     // finer Kb resolution for the progress values to see changes easily
0537     m_progressBar->setMaximum( bytesTotal / 1024 );
0538     m_progressBar->setValue( bytesReceived / 1024 );
0539     QString progress = "%1/%2 MB";
0540     m_progressBar->setFormat( progress.arg( bytesReceived / 1024 / 1024 ).arg( bytesTotal / 1024 / 1024 ) );
0541 }
0542 
0543 bool MonavConfigWidgetPrivate::canExecute( const QString &executable )
0544 {
0545     QString path = QProcessEnvironment::systemEnvironment().value(QStringLiteral("PATH"), QStringLiteral("/usr/local/bin:/usr/bin:/bin"));
0546     for( const QString &dir: path.split( QLatin1Char( ':' ) ) ) {
0547         QFileInfo application( QDir( dir ), executable );
0548         if ( application.exists() ) {
0549             return true;
0550         }
0551     }
0552 
0553     return false;
0554 }
0555 
0556 void MonavConfigWidget::mapInstalled( int exitStatus )
0557 {
0558     d->m_unpackProcess = nullptr;
0559     d->m_currentFile.remove();
0560     d->setBusy( false );
0561 
0562     if ( exitStatus == 0 ) {
0563         d->m_plugin->reloadMaps();
0564         d->updateInstalledMapsView();
0565         monavTabWidget->setCurrentIndex( 0 );
0566     } else {
0567         mDebug() << "Error when unpacking archive, process exited with status code " << exitStatus;
0568     }
0569 }
0570 
0571 void MonavConfigWidget::showEvent ( QShowEvent * event )
0572 {
0573     // Lazy initialization
0574     RoutingRunnerPlugin::ConfigWidget::showEvent( event );
0575     if ( !event->spontaneous() && !d->m_initialized ) {
0576         d->m_initialized = true;
0577         d->updateInstalledMapsView();
0578         QUrl url = QUrl( "http://files.kde.org/marble/newstuff/maps-monav.xml" );
0579         d->m_networkAccessManager.get( QNetworkRequest( url ) );
0580     }
0581 }
0582 
0583 void MonavConfigWidgetPrivate::updateInstalledMapsView()
0584 {
0585     m_mapsModel = m_plugin->installedMapsModel();
0586     m_mapsModel->setInstallableVersions( m_remoteVersions );
0587     m_filteredModel->setSourceModel( m_mapsModel );
0588     m_parent->m_installedMapsListView->setModel( m_mapsModel );
0589 
0590     m_parent->m_configureMapsListView->setColumnHidden( 1, true );
0591     m_parent->m_installedMapsListView->setColumnHidden( 2, true );
0592     m_parent->m_configureMapsListView->setColumnHidden( 3, true );
0593     m_parent->m_configureMapsListView->setColumnHidden( 4, true );
0594     m_parent->m_installedMapsListView->setColumnHidden( 5, true );
0595 
0596     m_parent->m_configureMapsListView->horizontalHeader()->setVisible( true );
0597     m_parent->m_installedMapsListView->horizontalHeader()->setVisible( true );
0598     m_parent->m_configureMapsListView->resizeColumnsToContents();
0599     m_parent->m_installedMapsListView->resizeColumnsToContents();
0600 
0601     updateTransportPreference();
0602     updateInstalledMapsViewButtons();
0603 }
0604 
0605 void MonavConfigWidgetPrivate::updateInstalledMapsViewButtons()
0606 {
0607     m_removeMapSignalMapper.removeMappings( m_parent );
0608     m_upgradeMapSignalMapper.removeMappings( m_parent );
0609     for( int i=0; i<m_mapsModel->rowCount(); ++i ) {
0610         {
0611             QPushButton* button = new QPushButton(QIcon(QStringLiteral(":/system-software-update.png")), QString());
0612             button->setAutoFillBackground( true );
0613             QModelIndex index = m_mapsModel->index( i, 3 );
0614             m_parent->m_installedMapsListView->setIndexWidget( index, button );
0615             m_upgradeMapSignalMapper.setMapping( button, index.row() );
0616             QObject::connect( button, SIGNAL(clicked()), &m_upgradeMapSignalMapper, SLOT(map()) );
0617             bool upgradable = m_mapsModel->data( index ).toBool();
0618             QString canUpgradeText = QObject::tr( "An update is available. Click to install it." );
0619             QString isLatestText = QObject::tr( "No update available. You are running the latest version." );
0620             button->setToolTip( upgradable ? canUpgradeText : isLatestText );
0621             button->setEnabled( upgradable );
0622         }
0623         {
0624             QPushButton* button = new QPushButton(QIcon(QStringLiteral(":/edit-delete.png")), QString());
0625             button->setAutoFillBackground( true );
0626             QModelIndex index = m_mapsModel->index( i, 4 );
0627             m_parent->m_installedMapsListView->setIndexWidget( index, button );
0628             m_removeMapSignalMapper.setMapping( button, index.row() );
0629             QObject::connect( button, SIGNAL(clicked()), &m_removeMapSignalMapper, SLOT(map()) );
0630             bool const writable = m_mapsModel->data( index ).toBool();
0631             button->setEnabled( writable );
0632         }
0633     }
0634     m_parent->m_installedMapsListView->resizeColumnsToContents();
0635 }
0636 
0637 void MonavConfigWidget::updateTransportTypeFilter( const QString &filter )
0638 {
0639     d->m_filteredModel->setFilterFixedString( filter );
0640     d->m_transport = filter;
0641     m_configureMapsListView->resizeColumnsToContents();
0642 }
0643 
0644 void MonavConfigWidget::removeMap( int index )
0645 {
0646     QMessageBox::StandardButtons buttons = QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel;
0647     QString text = tr( "Are you sure you want to delete this map from the system?" );
0648     if ( QMessageBox::question( this, tr( "Remove Map" ), text, buttons, QMessageBox::No ) == QMessageBox::Yes ) {
0649         d->m_mapsModel->deleteMapFiles( index );
0650         d->m_plugin->reloadMaps();
0651         d->updateInstalledMapsView();
0652     }
0653 }
0654 
0655 void MonavConfigWidget::upgradeMap( int index )
0656 {
0657     QString payload = d->m_mapsModel->payload( index );
0658     if ( !payload.isEmpty() ) {
0659         for( const MonavStuffEntry &entry: d->m_remoteMaps ) {
0660             if (entry.payload().endsWith(QLatin1Char('/') + payload)) {
0661                 d->m_currentDownload = entry.payload();
0662                 d->install();
0663                 return;
0664             }
0665         }
0666     }
0667 }
0668 
0669 void MonavConfigWidgetPrivate::setBusy( bool busy, const QString &message ) const
0670 {
0671     if ( busy ) {
0672         m_parent->m_stackedWidget->removeWidget( m_parent->m_settingsPage );
0673         m_parent->m_stackedWidget->addWidget( m_parent->m_progressPage );
0674     } else {
0675         m_parent->m_stackedWidget->removeWidget( m_parent->m_progressPage );
0676         m_parent->m_stackedWidget->addWidget( m_parent->m_settingsPage );
0677     }
0678 
0679     QString const defaultMessage = QObject::tr( "Nothing to do." );
0680     m_parent->m_progressLabel->setText( message.isEmpty() ? defaultMessage : message );
0681 }
0682 
0683 }
0684 
0685 #include "moc_MonavConfigWidget.cpp"