FlightGear next
AddonsModel.cxx
Go to the documentation of this file.
1// AddonsModel.cxx - part of GUI launcher using Qt5
2//
3// Written by Dan Wickstrom, started February 2019.
4//
5// Copyright (C) 2019 Daniel Wickstrom <daniel.c.wickstrom@gmail.com>
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21#include "config.h"
22
23#include <QDebug>
24#include <QUrl>
25#include <string>
26#include <simgear/misc/strutils.hxx>
27
28#include "AddonsModel.hxx"
30
32 QAbstractListModel(pr)
33{
34 m_roleToName[Qt::DisplayRole] = "display";
35 m_nameToRole["display"] = Qt::DisplayRole;
36
37 int roleValue = IdRole;
38
39 for (auto it = m_roles.begin(); it != m_roles.end(); ++it) {
40 QByteArray name = it->toUtf8();
41 m_roleToName[roleValue] = name;
42 m_nameToRole[*it] = roleValue++;
43 }
44}
45
50
51void AddonsModel::resetData(const QStringList& ndata)
52{
53 beginResetModel();
54#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
55 const auto newSet = QSet<QString>{ndata.begin(), ndata.end()};
56#else
57 const auto newSet = QSet<QString>::fromList(ndata);
58#endif
59 for(const auto& path : m_addonsList) {
60 if (!newSet.contains(path)) {
61 m_addonsMap.remove(path);
62 }
63 }
64 m_addonsList = ndata;
65 endResetModel();
66}
67
68int AddonsModel::rowCount(const QModelIndex& parent) const
69{
70 return m_addonsList.size();
71}
72
73
74QVariant AddonsModel::data(const QModelIndex& index, int role) const
75{
76 auto idx = index.row();
77 return get(idx, role);
78}
79
80QVariant AddonsModel::get(int idx, QString role) const
81{
82 int role_idx = m_nameToRole[role];
83 return get(idx, role_idx);
84}
85
86QVariant AddonsModel::get(int idx, int role) const
87{
88 if (idx >= 0 && idx < m_addonsList.size()) {
89 auto path = m_addonsList[idx];
90 if (!m_addonsMap.contains(path)) {
91 if ((role == PathRole) || (role == Qt::DisplayRole)) {
92 return path;
93 }
94
95 return {};
96 }
97
98 auto addon = m_addonsMap[path].addon;
99 if (!addon)
100 return {};
101
102 if (role == Qt::DisplayRole) {
103 QString name = QString::fromStdString(addon->getName());
104 QString desc = QString::fromStdString(addon->getShortDescription());
105 return tr("%1 - %2").arg(name).arg(desc);
106 }
107 else if (role == IdRole) {
108 return QString::fromStdString(addon->getId());
109 }
110 else if (role == NameRole) {
111 return QString::fromStdString(addon->getName());
112 }
113 else if (role == PathRole) {
114 return path;
115 }
116 else if (role == VersionRole) {
117 const auto v = addon->getVersion()->str();
118 return QString::fromStdString(v);
119 }
120 else if (role == AuthorsRole) {
121 QStringList authors;
122 for (auto author : addon->getAuthors()) {
123 authors.push_back(QString::fromStdString(author->getName()));
124 }
125 return authors;
126 }
127 else if (role == MaintainersRole) {
128 QStringList maintainers;
129 for (auto maintainer : addon->getMaintainers()) {
130 maintainers.push_back(QString::fromStdString(maintainer->getName()));
131 }
132 return maintainers;
133 }
134 else if (role == ShortDescriptionRole) {
135 return QString::fromStdString(addon->getShortDescription());
136 }
137 else if (role == LongDescriptionRole) {
138 return QString::fromStdString(addon->getLongDescription());
139 }
140 else if (role == LicenseDesignationRole) {
141 return QString::fromStdString(addon->getLicenseDesignation());
142 }
143 else if (role == LicenseUrlRole) {
144 return QUrl(QString::fromStdString(addon->getLicenseUrl()));
145 }
146 else if (role == TagsRole) {
147 QStringList tags;
148 for (auto tag : addon->getTags()) {
149 tags.push_back(QString::fromStdString(tag));
150 }
151 return tags;
152 }
153 else if (role == MinFGVersionRole) {
154 const auto v = addon->getMinFGVersionRequired();
155 if (v == "none")
156 return QStringLiteral("-");
157 return QString::fromStdString(v);
158 }
159 else if (role == MaxFGVersionRole) {
160 const auto v = addon->getMaxFGVersionRequired();
161 if (v == "none")
162 return QStringLiteral("-");
163 return QString::fromStdString(v);
164 }
165 else if (role == HomePageRole) {
166 return QUrl(QString::fromStdString(addon->getHomePage()));
167 }
168 else if (role == DownloadUrlRole) {
169 return QUrl(QString::fromStdString(addon->getDownloadUrl()));
170 }
171 else if (role == SupportUrlRole) {
172 return QUrl(QString::fromStdString(addon->getSupportUrl()));
173 }
174 else if (role == CodeRepoUrlRole) {
175 return QUrl(QString::fromStdString(addon->getCodeRepositoryUrl()));
176 }
177 else if (role == EnableRole) {
178 return QVariant(m_addonsMap[path].enable && checkVersion(path));
179 }
180 }
181 return QVariant();
182}
183
184
185bool AddonsModel::setData(const QModelIndex &index, const QVariant &value, int role)
186{
187 return false;
188}
189
191
192 if (!m_addonsMap.contains(path)) {
193 m_addonsList.push_back(path);
194 m_addonsMap[path].addon = addon;
195 m_addonsMap[path].enable = enable && checkVersion(path);
196 emit dataChanged(index(m_addonsList.size()-1), index(m_addonsList.size()-1));
197
198 return true;
199 }
200
201 return false;
202}
203
204Qt::ItemFlags AddonsModel::flags(const QModelIndex &index) const
205{
206 return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
207}
208
209QHash<int, QByteArray> AddonsModel::roleNames() const
210{
211 return m_roleToName;
212}
213
214void AddonsModel::enable(int row, bool enable)
215{
216 if ((row < 0) || (row >= m_addonsList.size())) {
217 return;
218 }
219
220 auto path = m_addonsList[row];
221 if (!m_addonsMap.contains(path))
222 return;
223
224 const bool wasEnabled = m_addonsMap[path].enable;
225 const bool nowEnabled = enable && checkVersion(path);
226 if (wasEnabled == nowEnabled)
227 return;
228
229 m_addonsMap[path].enable = nowEnabled;
230 const auto mindex = index(row, 0);
231 emit dataChanged(mindex, mindex, {EnableRole});
232 emit modulesChanged();
233}
234
235bool AddonsModel::checkVersion(QString path) const
236{
237 using namespace simgear;
238
239 if (!m_addonsMap.contains(path)) {
240 return false;
241 }
242
243 // Check that the FlightGear version satisfies the add-on requirements
244 std::string minFGversion = m_addonsMap[path].addon->getMinFGVersionRequired();
245 if (strutils::compare_versions(FLIGHTGEAR_VERSION, minFGversion) < 0) {
246 return false;
247 }
248
249 std::string maxFGversion = m_addonsMap[path].addon->getMaxFGVersionRequired();
250 if (maxFGversion != "none" &&
251 strutils::compare_versions(FLIGHTGEAR_VERSION, maxFGversion) > 0) {
252 return false;
253 }
254
255 return true;
256}
Q_INVOKABLE bool checkVersion(QString path) const
Q_INVOKABLE void enable(int index, bool enable)
bool append(QString path, flightgear::addons::AddonRef &addon, bool enable)
AddonsModel(QObject *pr)
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void resetData(const QStringList &ndata)
void modulesChanged()
Qt::ItemFlags flags(const QModelIndex &index) const override
QHash< int, QByteArray > roleNames() const override
int rowCount(const QModelIndex &parent) const override
QVariant data(const QModelIndex &index, int role) const override
Q_INVOKABLE QVariant get(int index, int role) const
const char * name
SGSharedPtr< Addon > AddonRef
Definition addon_fwd.hxx:46