Marble

SpeakersModel.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
4//
5
6#include "SpeakersModel.h"
7
8#include "MarbleDirs.h"
9#include "NewstuffModel.h"
10
11namespace Marble
12{
13
14class SpeakersModelItem
15{
16public:
17 QFileInfo m_file;
18
19 int m_newstuffIndex;
20
21 SpeakersModelItem();
22
23 static bool lessThan(const SpeakersModelItem &one, const SpeakersModelItem &two);
24};
25
26class SpeakersModelPrivate
27{
28public:
29 SpeakersModel *m_parent = nullptr;
30
31 QList<SpeakersModelItem> m_speakers;
32
33 NewstuffModel m_newstuffModel;
34
35 explicit SpeakersModelPrivate(SpeakersModel *parent);
36
37 void fillModel();
38
39 void handleInstallationProgress(int row, qreal progress);
40
41 void handleInstallation(int);
42
43 QHash<int, QByteArray> m_roleNames;
44};
45
46SpeakersModelItem::SpeakersModelItem()
47 : m_newstuffIndex(-1)
48{
49 // nothing to do
50}
51
52bool SpeakersModelItem::lessThan(const SpeakersModelItem &one, const SpeakersModelItem &two)
53{
54 return one.m_file.fileName() < two.m_file.fileName();
55}
56
57SpeakersModelPrivate::SpeakersModelPrivate(SpeakersModel *parent)
58 : m_parent(parent)
59{
60 m_newstuffModel.setTargetDirectory(MarbleDirs::localPath() + QLatin1StringView("/audio/speakers"));
61 m_newstuffModel.setProvider(QStringLiteral("http://edu.kde.org/marble/newstuff/speakers.xml"));
62 QObject::connect(&m_newstuffModel, SIGNAL(modelReset()), m_parent, SLOT(fillModel()));
63 QObject::connect(&m_newstuffModel, SIGNAL(installationProgressed(int, qreal)), m_parent, SLOT(handleInstallationProgress(int, qreal)));
64 QObject::connect(&m_newstuffModel, SIGNAL(installationFinished(int)), m_parent, SLOT(handleInstallation(int)));
65}
66
67void SpeakersModelPrivate::fillModel()
68{
69 m_speakers.clear();
70
71 QStringList const baseDirs = QStringList() << MarbleDirs::systemPath() << MarbleDirs::localPath();
72 for (const QString &baseDir : baseDirs) {
73 const QString base = baseDir + QLatin1StringView("/audio/speakers/");
74
76 QFileInfoList subdirs = QDir(base).entryInfoList(filter, QDir::Name);
77 for (const QFileInfo &file : subdirs) {
78 SpeakersModelItem item;
79 item.m_file = file;
80 m_speakers << item;
81 }
82 }
83
84 for (int i = 0; i < m_newstuffModel.rowCount(); ++i) {
85 QModelIndex const index = m_newstuffModel.index(i);
86 QString const name = m_newstuffModel.data(index).toString();
87 bool exists = false;
88 for (int j = 0; j < m_speakers.size() && !exists; ++j) {
89 SpeakersModelItem &item = m_speakers[j];
90 if (item.m_file.fileName() == name) {
91 item.m_newstuffIndex = i;
92 exists = true;
93 }
94 }
95
96 if (!exists) {
97 SpeakersModelItem item;
98 QString const path = QStringLiteral("%1/audio/speakers/%2");
99 item.m_file = QFileInfo(path.arg(MarbleDirs::localPath(), name));
100 item.m_newstuffIndex = i;
101 m_speakers << item;
102 }
103 }
104
105 std::sort(m_speakers.begin(), m_speakers.end(), SpeakersModelItem::lessThan);
106 m_parent->beginResetModel();
107 m_parent->endResetModel();
108 Q_EMIT m_parent->countChanged();
109}
110
111void SpeakersModelPrivate::handleInstallation(int row)
112{
113 for (int j = 0; j < m_speakers.size(); ++j) {
114 if (m_speakers[j].m_newstuffIndex == row) {
115 m_speakers[j].m_file.refresh();
116 QModelIndex const affected = m_parent->index(j);
117 Q_EMIT m_parent->dataChanged(affected, affected);
118 Q_EMIT m_parent->installationFinished(j);
119 }
120 }
121}
122
123void SpeakersModelPrivate::handleInstallationProgress(int row, qreal progress)
124{
125 for (int j = 0; j < m_speakers.size(); ++j) {
126 if (m_speakers[j].m_newstuffIndex == row) {
127 Q_EMIT m_parent->installationProgressed(j, progress);
128 }
129 }
130}
131
132SpeakersModel::SpeakersModel(QObject *parent)
133 : QAbstractListModel(parent)
134 , d(new SpeakersModelPrivate(this))
135{
137 roles[Path] = "path";
138 roles[Name] = "name";
139 roles[IsLocal] = "isLocal";
140 roles[IsRemote] = "isRemote";
141 d->m_roleNames = roles;
142
143 d->fillModel();
144}
145
146SpeakersModel::~SpeakersModel()
147{
148 delete d;
149}
150
151int SpeakersModel::rowCount(const QModelIndex &parent) const
152{
153 if (!parent.isValid()) {
154 return d->m_speakers.size();
155 }
156
157 return 0;
158}
159
160QVariant SpeakersModel::data(const QModelIndex &index, int role) const
161{
162 if (index.isValid() && index.row() >= 0 && index.row() < d->m_speakers.size()) {
163 switch (role) {
164 case Qt::DisplayRole:
165 return d->m_speakers.at(index.row()).m_file.fileName();
166 case Path:
167 return d->m_speakers.at(index.row()).m_file.absoluteFilePath();
168 case Name:
169 return d->m_speakers.at(index.row()).m_file.fileName();
170 case IsLocal:
171 return d->m_speakers.at(index.row()).m_file.exists();
172 case IsRemote:
173 return d->m_speakers.at(index.row()).m_newstuffIndex >= 0;
174 }
175 }
176
177 return {};
178}
179
180QHash<int, QByteArray> SpeakersModel::roleNames() const
181{
182 return d->m_roleNames;
183}
184
185int SpeakersModel::indexOf(const QString &name)
186{
187 for (int i = 0; i < d->m_speakers.size(); ++i) {
188 if (d->m_speakers[i].m_file.absoluteFilePath() == name || d->m_speakers[i].m_file.fileName() == name) {
189 return i;
190 }
191 }
192 return -1;
193}
194
195QString SpeakersModel::path(int index)
196{
197 if (index >= 0 && index <= d->m_speakers.size()) {
198 return d->m_speakers[index].m_file.absoluteFilePath();
199 }
200 return {};
201}
202
203void SpeakersModel::install(int index)
204{
205 if (index >= 0 && index < d->m_speakers.size()) {
206 if (d->m_speakers[index].m_newstuffIndex >= 0) {
207 d->m_newstuffModel.install(d->m_speakers[index].m_newstuffIndex);
208 }
209 }
210}
211
212bool SpeakersModel::isLocal(int idx) const
213{
214 return data(index(idx), IsLocal).toBool();
215}
216
217bool SpeakersModel::isRemote(int idx) const
218{
219 return data(index(idx), IsRemote).toBool();
220}
221
222int SpeakersModel::count() const
223{
224 return rowCount();
225}
226
227}
228
229#include "moc_SpeakersModel.cpp"
QString name(GameStandardAction id)
QString path(const QString &relativePath)
Binds a QML item to a specific geodetic location in screen coordinates.
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
bool isValid() const const
int row() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
QChar * data()
DisplayRole
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 8 2024 12:02:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.