File indexing completed on 2024-04-28 03:49:31

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "SpeakersModel.h"
0007 
0008 #include "MarbleDirs.h"
0009 #include "NewstuffModel.h"
0010 
0011 namespace Marble
0012 {
0013 
0014 class SpeakersModelItem
0015 {
0016 public:
0017     QFileInfo m_file;
0018 
0019     int m_newstuffIndex;
0020 
0021     SpeakersModelItem();
0022 
0023     static bool lessThan( const SpeakersModelItem& one, const SpeakersModelItem& two );
0024 };
0025 
0026 class SpeakersModelPrivate
0027 {
0028 public:
0029     SpeakersModel* m_parent;
0030 
0031     QList<SpeakersModelItem> m_speakers;
0032 
0033     NewstuffModel m_newstuffModel;
0034 
0035     explicit SpeakersModelPrivate( SpeakersModel* parent );
0036 
0037     void fillModel();
0038 
0039     void handleInstallationProgress( int row, qreal progress );
0040 
0041     void handleInstallation( int );
0042 
0043     QHash<int, QByteArray> m_roleNames;
0044 };
0045 
0046 SpeakersModelItem::SpeakersModelItem() : m_newstuffIndex( -1 )
0047 {
0048     // nothing to do
0049 }
0050 
0051 bool SpeakersModelItem::lessThan( const SpeakersModelItem& one, const SpeakersModelItem& two )
0052 {
0053     return one.m_file.fileName() < two.m_file.fileName();
0054 }
0055 
0056 SpeakersModelPrivate::SpeakersModelPrivate( SpeakersModel* parent ) :
0057     m_parent( parent )
0058 {
0059     m_newstuffModel.setTargetDirectory(MarbleDirs::localPath() + QLatin1String("/audio/speakers"));
0060     m_newstuffModel.setProvider( "http://edu.kde.org/marble/newstuff/speakers.xml" );
0061     QObject::connect( &m_newstuffModel, SIGNAL(modelReset()), m_parent, SLOT(fillModel()) );
0062     QObject::connect( &m_newstuffModel, SIGNAL(installationProgressed(int,qreal)),
0063                       m_parent, SLOT(handleInstallationProgress(int,qreal)) );
0064     QObject::connect( &m_newstuffModel, SIGNAL(installationFinished(int)), m_parent, SLOT(handleInstallation(int)) );
0065 }
0066 
0067 void SpeakersModelPrivate::fillModel()
0068 {
0069     m_speakers.clear();
0070 
0071     QStringList const baseDirs = QStringList() << MarbleDirs::systemPath() << MarbleDirs::localPath();
0072     for ( const QString &baseDir: baseDirs ) {
0073         const QString base = baseDir + QLatin1String("/audio/speakers/");
0074 
0075         QDir::Filters filter = QDir::Readable | QDir::Dirs | QDir::NoDotAndDotDot;
0076         QFileInfoList subdirs = QDir( base ).entryInfoList( filter, QDir::Name );
0077         for( const QFileInfo &file: subdirs ) {
0078             SpeakersModelItem item;
0079             item.m_file = file;
0080             m_speakers << item;
0081         }
0082     }
0083 
0084     for ( int i=0; i<m_newstuffModel.rowCount(); ++i ) {
0085         QModelIndex const index = m_newstuffModel.index( i );
0086         QString const name = m_newstuffModel.data( index ).toString();
0087         bool exists = false;
0088         for ( int j=0; j<m_speakers.size() && !exists; ++j ) {
0089             SpeakersModelItem &item = m_speakers[j];
0090             if ( item.m_file.fileName() == name ) {
0091                 item.m_newstuffIndex = i;
0092                 exists = true;
0093             }
0094         }
0095 
0096         if ( !exists ) {
0097             SpeakersModelItem item;
0098             QString const path = "%1/audio/speakers/%2";
0099             item.m_file = QFileInfo( path.arg( MarbleDirs::localPath(), name ) );
0100             item.m_newstuffIndex = i;
0101             m_speakers << item;
0102         }
0103     }
0104 
0105     std::sort(m_speakers.begin(), m_speakers.end(), SpeakersModelItem::lessThan);
0106     m_parent->beginResetModel();
0107     m_parent->endResetModel();
0108     emit m_parent->countChanged();
0109 }
0110 
0111 void SpeakersModelPrivate::handleInstallation( int row )
0112 {
0113     for ( int j=0; j<m_speakers.size(); ++j ) {
0114         if ( m_speakers[j].m_newstuffIndex == row ) {
0115             m_speakers[j].m_file.refresh();
0116             QModelIndex const affected = m_parent->index( j );
0117             emit m_parent->dataChanged( affected, affected );
0118             emit m_parent->installationFinished( j );
0119         }
0120     }
0121 }
0122 
0123 void SpeakersModelPrivate::handleInstallationProgress( int row, qreal progress )
0124 {
0125     for ( int j=0; j<m_speakers.size(); ++j ) {
0126         if ( m_speakers[j].m_newstuffIndex == row ) {
0127             emit m_parent->installationProgressed( j, progress );
0128         }
0129     }
0130 }
0131 
0132 SpeakersModel::SpeakersModel( QObject *parent ) :
0133     QAbstractListModel( parent ), d( new SpeakersModelPrivate( this ) )
0134 {
0135     QHash<int,QByteArray> roles;
0136     roles[Path] = "path";
0137     roles[Name] = "name";
0138     roles[IsLocal] = "isLocal";
0139     roles[IsRemote] = "isRemote";
0140     d->m_roleNames = roles;
0141 
0142     d->fillModel();
0143 }
0144 
0145 SpeakersModel::~SpeakersModel()
0146 {
0147     delete d;
0148 }
0149 
0150 int SpeakersModel::rowCount ( const QModelIndex &parent ) const
0151 {
0152     if ( !parent.isValid() ) {
0153         return d->m_speakers.size();
0154     }
0155 
0156     return 0;
0157 }
0158 
0159 QVariant SpeakersModel::data ( const QModelIndex &index, int role ) const
0160 {
0161     if ( index.isValid() && index.row() >= 0 && index.row() < d->m_speakers.size() ) {
0162         switch ( role ) {
0163         case Qt::DisplayRole: return d->m_speakers.at( index.row() ).m_file.fileName();
0164         case Path: return d->m_speakers.at( index.row() ).m_file.absoluteFilePath();
0165         case Name: return d->m_speakers.at( index.row() ).m_file.fileName();
0166         case IsLocal: return d->m_speakers.at( index.row() ).m_file.exists();
0167         case IsRemote: return d->m_speakers.at( index.row() ).m_newstuffIndex >= 0;
0168         }
0169     }
0170 
0171     return QVariant();
0172 }
0173 
0174 QHash<int, QByteArray> SpeakersModel::roleNames() const
0175 {
0176     return d->m_roleNames;
0177 }
0178 
0179 int SpeakersModel::indexOf( const QString &name )
0180 {
0181     for( int i=0; i<d->m_speakers.size(); ++i ) {
0182         if ( d->m_speakers[i].m_file.absoluteFilePath() == name || d->m_speakers[i].m_file.fileName() == name ) {
0183             return i;
0184         }
0185     }
0186     return -1;
0187 }
0188 
0189 QString SpeakersModel::path( int index )
0190 {
0191     if ( index >= 0 && index <= d->m_speakers.size() ) {
0192         return d->m_speakers[index].m_file.absoluteFilePath();
0193     }
0194     return QString();
0195 }
0196 
0197 void SpeakersModel::install( int index )
0198 {
0199     if ( index >= 0 && index < d->m_speakers.size() ) {
0200         if ( d->m_speakers[index].m_newstuffIndex >= 0 ) {
0201             d->m_newstuffModel.install( d->m_speakers[index].m_newstuffIndex );
0202         }
0203     }
0204 }
0205 
0206 bool SpeakersModel::isLocal( int idx ) const
0207 {
0208     return data( index( idx ), IsLocal ).toBool();
0209 }
0210 
0211 bool SpeakersModel::isRemote( int idx ) const
0212 {
0213     return data( index( idx ), IsRemote ).toBool();
0214 }
0215 
0216 int SpeakersModel::count() const
0217 {
0218     return rowCount();
0219 }
0220 
0221 }
0222 
0223 #include "moc_SpeakersModel.cpp"