2015-03-10 00:13:55 +00:00
|
|
|
// AircraftModel.cxx - part of GUI launcher using Qt5
|
|
|
|
//
|
|
|
|
// Written by James Turner, started March 2015.
|
|
|
|
//
|
2015-03-13 16:29:20 +00:00
|
|
|
// Copyright (C) 2015 James Turner <zakalawe@mac.com>
|
2015-03-10 00:13:55 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
#include "AircraftModel.hxx"
|
|
|
|
|
|
|
|
#include <QSettings>
|
|
|
|
#include <QDebug>
|
2015-08-03 20:53:56 +00:00
|
|
|
#include <QSharedPointer>
|
2020-04-01 09:47:29 +00:00
|
|
|
#include <QSettings>
|
2015-03-10 00:13:55 +00:00
|
|
|
|
|
|
|
// Simgear
|
|
|
|
#include <simgear/props/props_io.hxx>
|
|
|
|
#include <simgear/structure/exception.hxx>
|
|
|
|
#include <simgear/misc/sg_path.hxx>
|
2015-03-13 16:29:20 +00:00
|
|
|
#include <simgear/package/Package.hxx>
|
|
|
|
#include <simgear/package/Catalog.hxx>
|
|
|
|
#include <simgear/package/Install.hxx>
|
2015-03-10 00:13:55 +00:00
|
|
|
|
|
|
|
// FlightGear
|
|
|
|
#include <Main/globals.hxx>
|
2017-06-22 09:45:47 +00:00
|
|
|
#include <Include/version.h>
|
2015-03-10 00:13:55 +00:00
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
#include "QmlAircraftInfo.hxx"
|
2020-04-04 08:20:23 +00:00
|
|
|
#include "FavouriteAircraftData.hxx"
|
2017-10-09 20:53:26 +00:00
|
|
|
|
2015-03-13 16:29:20 +00:00
|
|
|
using namespace simgear::pkg;
|
|
|
|
|
2020-02-24 11:32:43 +00:00
|
|
|
bool isPackageFailure(Delegate::StatusCode status)
|
|
|
|
{
|
|
|
|
switch (status) {
|
|
|
|
case Delegate::STATUS_SUCCESS:
|
|
|
|
case Delegate::STATUS_REFRESHED:
|
|
|
|
case Delegate::STATUS_IN_PROGRESS:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
class PackageDelegate : public simgear::pkg::Delegate
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
PackageDelegate(AircraftItemModel* model) :
|
|
|
|
m_model(model)
|
|
|
|
{
|
|
|
|
m_model->m_packageRoot->addDelegate(this);
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2018-07-23 08:10:08 +00:00
|
|
|
~PackageDelegate() override
|
2015-08-03 20:53:56 +00:00
|
|
|
{
|
|
|
|
m_model->m_packageRoot->removeDelegate(this);
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
protected:
|
2020-03-26 16:56:01 +00:00
|
|
|
void catalogRefreshed(CatalogRef aCatalog, StatusCode aReason) override;
|
2017-06-22 09:45:47 +00:00
|
|
|
void startInstall(InstallRef aInstall) override
|
2015-08-03 20:53:56 +00:00
|
|
|
{
|
|
|
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
|
|
|
m_model->dataChanged(mi, mi);
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2017-06-22 09:45:47 +00:00
|
|
|
void installProgress(InstallRef aInstall, unsigned int bytes, unsigned int total) override
|
2015-08-03 20:53:56 +00:00
|
|
|
{
|
2020-02-24 11:32:43 +00:00
|
|
|
Q_UNUSED(bytes)
|
|
|
|
Q_UNUSED(total)
|
2015-08-03 20:53:56 +00:00
|
|
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
|
|
|
m_model->dataChanged(mi, mi);
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2017-06-22 09:45:47 +00:00
|
|
|
void finishInstall(InstallRef aInstall, StatusCode aReason) override
|
2015-08-03 20:53:56 +00:00
|
|
|
{
|
|
|
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
|
|
|
m_model->dataChanged(mi, mi);
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
if ((aReason != USER_CANCELLED) && (aReason != STATUS_SUCCESS)) {
|
|
|
|
m_model->installFailed(mi, aReason);
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
if (aReason == STATUS_SUCCESS) {
|
|
|
|
m_model->installSucceeded(mi);
|
|
|
|
}
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2017-06-22 09:45:47 +00:00
|
|
|
void availablePackagesChanged() override
|
2015-11-23 17:59:16 +00:00
|
|
|
{
|
|
|
|
m_model->refreshPackages();
|
|
|
|
}
|
|
|
|
|
2017-06-22 09:45:47 +00:00
|
|
|
void installStatusChanged(InstallRef aInstall, StatusCode aReason) override
|
|
|
|
{
|
2020-02-24 11:32:43 +00:00
|
|
|
Q_UNUSED(aReason)
|
2017-06-22 09:45:47 +00:00
|
|
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
|
|
|
m_model->dataChanged(mi, mi);
|
|
|
|
}
|
|
|
|
|
|
|
|
void finishUninstall(const PackageRef& pkg) override
|
|
|
|
{
|
|
|
|
QModelIndex mi(indexForPackage(pkg));
|
|
|
|
m_model->dataChanged(mi, mi);
|
|
|
|
}
|
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
private:
|
|
|
|
QModelIndex indexForPackage(const PackageRef& ref) const
|
|
|
|
{
|
2016-11-16 21:27:00 +00:00
|
|
|
auto it = std::find(m_model->m_packages.begin(),
|
|
|
|
m_model->m_packages.end(), ref);
|
2015-08-03 20:53:56 +00:00
|
|
|
if (it == m_model->m_packages.end()) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2020-04-02 15:13:12 +00:00
|
|
|
const int offset = static_cast<int>(std::distance(m_model->m_packages.begin(), it));
|
2017-10-09 20:53:26 +00:00
|
|
|
return m_model->index(offset + m_model->m_cachedLocalAircraftCount);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
AircraftItemModel* m_model;
|
|
|
|
};
|
|
|
|
|
2020-03-26 16:56:01 +00:00
|
|
|
void PackageDelegate::catalogRefreshed(CatalogRef aCatalog, StatusCode aReason)
|
|
|
|
{
|
|
|
|
if (aReason == STATUS_IN_PROGRESS) {
|
|
|
|
// nothing to do
|
|
|
|
} else if ((aReason == STATUS_REFRESHED) || (aReason == STATUS_SUCCESS)) {
|
|
|
|
m_model->refreshPackages();
|
2020-04-02 15:13:12 +00:00
|
|
|
} else if (aReason == FAIL_VERSION) {
|
|
|
|
// silent about this
|
2020-03-26 16:56:01 +00:00
|
|
|
} else {
|
|
|
|
qWarning() << "failed refresh of"
|
|
|
|
<< QString::fromStdString(aCatalog->url()) << ":" << aReason << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/// \brief AircraftItemModel::AircraftItemModel
|
|
|
|
/// \param pr
|
|
|
|
///
|
2017-02-06 14:09:07 +00:00
|
|
|
AircraftItemModel::AircraftItemModel(QObject* pr) :
|
2016-11-07 19:49:33 +00:00
|
|
|
QAbstractListModel(pr)
|
2015-03-10 00:13:55 +00:00
|
|
|
{
|
2017-10-09 20:53:26 +00:00
|
|
|
auto cache = LocalAircraftCache::instance();
|
|
|
|
connect(cache, &LocalAircraftCache::scanStarted,
|
|
|
|
this, &AircraftItemModel::onScanStarted);
|
|
|
|
connect(cache, &LocalAircraftCache::addedItems,
|
|
|
|
this, &AircraftItemModel::onScanAddedItems);
|
2017-12-15 15:42:36 +00:00
|
|
|
connect(cache, &LocalAircraftCache::cleared,
|
|
|
|
this, &AircraftItemModel::onLocalCacheCleared);
|
2015-03-11 23:20:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AircraftItemModel::~AircraftItemModel()
|
|
|
|
{
|
2015-09-28 00:44:29 +00:00
|
|
|
delete m_delegate;
|
2015-03-11 23:20:18 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 15:10:06 +00:00
|
|
|
void AircraftItemModel::setPackageRoot(const simgear::pkg::RootRef& root)
|
|
|
|
{
|
|
|
|
if (m_packageRoot) {
|
|
|
|
delete m_delegate;
|
2017-12-15 15:42:36 +00:00
|
|
|
m_delegate = nullptr;
|
2016-03-24 15:10:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_packageRoot = root;
|
|
|
|
|
|
|
|
if (m_packageRoot) {
|
|
|
|
m_delegate = new PackageDelegate(this);
|
|
|
|
// packages may already be refreshed, so pull now
|
|
|
|
refreshPackages();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
void AircraftItemModel::onScanStarted()
|
2015-03-11 23:20:18 +00:00
|
|
|
{
|
2017-10-09 20:53:26 +00:00
|
|
|
const int numToRemove = m_cachedLocalAircraftCount;
|
|
|
|
if (numToRemove > 0) {
|
2017-06-22 09:45:47 +00:00
|
|
|
int lastRow = numToRemove - 1;
|
|
|
|
beginRemoveRows(QModelIndex(), 0, lastRow);
|
|
|
|
m_delegateStates.remove(0, numToRemove);
|
2017-10-09 20:53:26 +00:00
|
|
|
m_cachedLocalAircraftCount = 0;
|
|
|
|
endRemoveRows();
|
2015-03-10 00:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
void AircraftItemModel::refreshPackages()
|
|
|
|
{
|
2016-04-15 16:06:53 +00:00
|
|
|
simgear::pkg::PackageList newPkgs = m_packageRoot->allPackages();
|
2017-10-09 20:53:26 +00:00
|
|
|
const int firstRow = m_cachedLocalAircraftCount;
|
2018-07-23 08:10:08 +00:00
|
|
|
const int newSize = static_cast<int>(newPkgs.size());
|
2016-11-16 21:27:00 +00:00
|
|
|
const int newTotalSize = firstRow + newSize;
|
2016-04-15 16:06:53 +00:00
|
|
|
|
|
|
|
if (m_packages.size() != newPkgs.size()) {
|
2018-07-23 08:10:08 +00:00
|
|
|
const int oldSize = static_cast<int>(m_packages.size());
|
2016-04-15 16:06:53 +00:00
|
|
|
if (newSize > oldSize) {
|
|
|
|
// growing
|
|
|
|
int firstNewRow = firstRow + oldSize;
|
|
|
|
int lastNewRow = firstRow + newSize - 1;
|
|
|
|
beginInsertRows(QModelIndex(), firstNewRow, lastNewRow);
|
|
|
|
m_packages = newPkgs;
|
2016-11-16 21:27:00 +00:00
|
|
|
m_delegateStates.resize(newTotalSize);
|
2016-04-15 16:06:53 +00:00
|
|
|
endInsertRows();
|
|
|
|
} else {
|
|
|
|
// shrinking
|
|
|
|
int firstOldRow = firstRow + newSize;
|
|
|
|
int lastOldRow = firstRow + oldSize - 1;
|
|
|
|
beginRemoveRows(QModelIndex(), firstOldRow, lastOldRow);
|
|
|
|
m_packages = newPkgs;
|
2016-11-16 21:27:00 +00:00
|
|
|
m_delegateStates.resize(newTotalSize);
|
2016-04-15 16:06:53 +00:00
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_packages = newPkgs;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit dataChanged(index(firstRow), index(firstRow + newSize - 1));
|
2018-07-23 08:10:08 +00:00
|
|
|
emit contentsChanged();
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
|
|
|
|
2018-07-23 08:10:08 +00:00
|
|
|
int AircraftItemModel::rowCount(const QModelIndex&) const
|
2015-08-03 20:53:56 +00:00
|
|
|
{
|
2018-07-23 08:10:08 +00:00
|
|
|
return m_cachedLocalAircraftCount + static_cast<int>(m_packages.size());
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:13:55 +00:00
|
|
|
QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
2015-03-13 16:29:20 +00:00
|
|
|
{
|
2016-04-15 16:06:53 +00:00
|
|
|
int row = index.row();
|
2016-11-16 21:27:00 +00:00
|
|
|
if (role == AircraftVariantRole) {
|
|
|
|
return m_delegateStates.at(row).variant;
|
|
|
|
}
|
2015-08-03 20:53:56 +00:00
|
|
|
|
2020-04-01 09:47:29 +00:00
|
|
|
if (role == AircraftIsFavouriteRole) {
|
|
|
|
// recursive call here, hope that's okay
|
|
|
|
const auto uri = data(index, AircraftURIRole).toUrl();
|
2020-04-04 08:20:23 +00:00
|
|
|
return FavouriteAircraftData::instance()->isFavourite(uri);
|
2020-04-01 09:47:29 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
if (row >= m_cachedLocalAircraftCount) {
|
2020-02-24 11:32:43 +00:00
|
|
|
quint32 packageIndex = static_cast<quint32>(row - m_cachedLocalAircraftCount);
|
2015-08-03 20:53:56 +00:00
|
|
|
const PackageRef& pkg(m_packages[packageIndex]);
|
|
|
|
InstallRef ex = pkg->existingInstall();
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
if (role == AircraftInstallPercentRole) {
|
|
|
|
return ex.valid() ? ex->downloadedPercent() : 0;
|
|
|
|
} else if (role == AircraftInstallDownloadedSizeRole) {
|
|
|
|
return static_cast<quint64>(ex.valid() ? ex->downloadedBytes() : 0);
|
2016-11-30 21:33:16 +00:00
|
|
|
} else if (role == AircraftPackageRefRole ) {
|
|
|
|
return QVariant::fromValue(pkg);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2016-11-16 21:27:00 +00:00
|
|
|
return dataFromPackage(pkg, m_delegateStates.at(row), role);
|
2015-08-03 20:53:56 +00:00
|
|
|
} else {
|
2017-10-09 20:53:26 +00:00
|
|
|
const AircraftItemPtr item(LocalAircraftCache::instance()->itemAt(row));
|
2016-11-16 21:27:00 +00:00
|
|
|
return dataFromItem(item, m_delegateStates.at(row), role);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
|
2016-11-16 21:27:00 +00:00
|
|
|
QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, const DelegateState& state, int role) const
|
2015-03-13 16:29:20 +00:00
|
|
|
{
|
|
|
|
if (role == AircraftVariantCountRole) {
|
|
|
|
return item->variants.count();
|
|
|
|
}
|
|
|
|
|
2017-02-06 14:09:07 +00:00
|
|
|
if (role >= AircraftVariantDescriptionRole) {
|
2015-03-13 16:29:20 +00:00
|
|
|
int variantIndex = role - AircraftVariantDescriptionRole;
|
2018-07-02 13:11:01 +00:00
|
|
|
if (variantIndex == 0) {
|
2020-06-19 09:45:47 +00:00
|
|
|
return item->name();
|
2018-07-02 13:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Q_ASSERT(variantIndex < item->variants.size());
|
2020-06-19 09:45:47 +00:00
|
|
|
return item->variants.at(variantIndex)->name();
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
|
2016-11-16 21:27:00 +00:00
|
|
|
if (state.variant) {
|
|
|
|
if (state.variant <= static_cast<quint32>(item->variants.count())) {
|
2015-03-13 16:29:20 +00:00
|
|
|
// show the selected variant
|
2016-11-16 21:27:00 +00:00
|
|
|
item = item->variants.at(state.variant - 1);
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (role == Qt::DisplayRole) {
|
2020-06-19 09:45:47 +00:00
|
|
|
if (item->name().isEmpty()) {
|
2015-09-26 17:41:32 +00:00
|
|
|
return tr("Missing description for: %1").arg(item->baseName());
|
|
|
|
}
|
|
|
|
|
2020-06-19 09:45:47 +00:00
|
|
|
return item->name();
|
2015-03-13 16:29:20 +00:00
|
|
|
} else if (role == AircraftPathRole) {
|
|
|
|
return item->path;
|
|
|
|
} else if (role == AircraftAuthorsRole) {
|
|
|
|
return item->authors;
|
|
|
|
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
|
|
|
return item->ratings[role - AircraftRatingRole];
|
|
|
|
} else if (role == AircraftPackageIdRole) {
|
|
|
|
// can we fake an ID? otherwise fall through to a null variant
|
|
|
|
} else if (role == AircraftPackageStatusRole) {
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageInstalled; // always the case
|
2015-03-13 16:29:20 +00:00
|
|
|
} else if (role == Qt::ToolTipRole) {
|
|
|
|
return item->path;
|
2015-08-03 20:53:56 +00:00
|
|
|
} else if (role == AircraftURIRole) {
|
|
|
|
return QUrl::fromLocalFile(item->path);
|
2015-03-16 16:34:22 +00:00
|
|
|
} else if (role == AircraftHasRatingsRole) {
|
|
|
|
bool have = false;
|
|
|
|
for (int i=0; i<4; ++i) {
|
|
|
|
have |= (item->ratings[i] > 0);
|
|
|
|
}
|
|
|
|
return have;
|
2015-03-16 15:07:44 +00:00
|
|
|
} else if (role == AircraftLongDescriptionRole) {
|
2020-06-19 09:45:47 +00:00
|
|
|
return item->description();
|
2015-11-17 07:36:54 +00:00
|
|
|
} else if (role == AircraftIsHelicopterRole) {
|
|
|
|
return item->usesHeliports;
|
|
|
|
} else if (role == AircraftIsSeaplaneRole) {
|
|
|
|
return item->usesSeaports;
|
2017-06-22 09:45:47 +00:00
|
|
|
} else if ((role == AircraftInstallDownloadedSizeRole) ||
|
|
|
|
(role == AircraftPackageSizeRole))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
} else if (role == AircraftStatusRole) {
|
2017-10-09 20:53:26 +00:00
|
|
|
return item->status(0 /* variant is always 0 */);
|
2017-06-22 09:45:47 +00:00
|
|
|
} else if (role == AircraftMinVersionRole) {
|
|
|
|
return item->minFGVersion;
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2016-11-16 21:27:00 +00:00
|
|
|
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, const DelegateState& state, int role) const
|
2015-03-13 16:29:20 +00:00
|
|
|
{
|
2017-02-06 14:09:07 +00:00
|
|
|
if (role >= AircraftVariantDescriptionRole) {
|
2020-04-02 15:13:12 +00:00
|
|
|
const unsigned int variantIndex = static_cast<unsigned int>(role - AircraftVariantDescriptionRole);
|
2016-01-11 05:46:44 +00:00
|
|
|
QString desc = QString::fromStdString(item->nameForVariant(variantIndex));
|
|
|
|
if (desc.isEmpty()) {
|
|
|
|
desc = tr("Missing description for: %1").arg(QString::fromStdString(item->id()));
|
|
|
|
}
|
|
|
|
return desc;
|
2016-01-04 02:58:03 +00:00
|
|
|
}
|
|
|
|
|
2015-03-13 16:29:20 +00:00
|
|
|
if (role == Qt::DisplayRole) {
|
2016-11-16 21:27:00 +00:00
|
|
|
QString desc = QString::fromStdString(item->nameForVariant(state.variant));
|
2016-01-11 05:46:44 +00:00
|
|
|
if (desc.isEmpty()) {
|
|
|
|
desc = tr("Missing description for: %1").arg(QString::fromStdString(item->id()));
|
|
|
|
}
|
|
|
|
return desc;
|
2015-03-13 16:29:20 +00:00
|
|
|
} else if (role == AircraftPathRole) {
|
2015-08-03 20:53:56 +00:00
|
|
|
InstallRef i = item->existingInstall();
|
|
|
|
if (i.valid()) {
|
2016-06-21 11:28:35 +00:00
|
|
|
return QString::fromStdString(i->primarySetPath().utf8Str());
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-03-13 16:29:20 +00:00
|
|
|
} else if (role == AircraftPackageIdRole) {
|
2016-11-16 21:27:00 +00:00
|
|
|
return QString::fromStdString(item->variants()[state.variant]);
|
2015-03-13 16:29:20 +00:00
|
|
|
} else if (role == AircraftPackageStatusRole) {
|
2015-08-03 20:53:56 +00:00
|
|
|
InstallRef i = item->existingInstall();
|
|
|
|
if (i.valid()) {
|
2015-03-13 16:29:20 +00:00
|
|
|
if (i->isDownloading()) {
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageDownloading;
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
2015-08-03 20:53:56 +00:00
|
|
|
if (i->isQueued()) {
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageQueued;
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-03-13 16:29:20 +00:00
|
|
|
if (i->hasUpdate()) {
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageUpdateAvailable;
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
|
2020-02-24 11:32:43 +00:00
|
|
|
const auto status = i->status();
|
|
|
|
if (isPackageFailure(status))
|
|
|
|
return LocalAircraftCache::PackageInstallFailed;
|
|
|
|
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageInstalled;
|
2015-03-13 16:29:20 +00:00
|
|
|
} else {
|
2017-10-13 15:48:24 +00:00
|
|
|
return LocalAircraftCache::PackageNotInstalled;
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
2016-01-04 02:58:03 +00:00
|
|
|
} else if (role == AircraftVariantCountRole) {
|
|
|
|
// this value wants the number of aditional variants, i.e not
|
|
|
|
// including the primary. Hence the -1 term.
|
|
|
|
return static_cast<quint32>(item->variants().size() - 1);
|
2015-08-03 20:53:56 +00:00
|
|
|
} else if (role == AircraftAuthorsRole) {
|
2016-11-25 22:45:48 +00:00
|
|
|
std::string authors = item->getLocalisedProp("author", state.variant);
|
|
|
|
if (!authors.empty()) {
|
|
|
|
return QString::fromStdString(authors);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
2015-03-16 15:07:44 +00:00
|
|
|
} else if (role == AircraftLongDescriptionRole) {
|
2016-11-25 22:45:48 +00:00
|
|
|
std::string longDesc = item->getLocalisedProp("description", state.variant);
|
|
|
|
return QString::fromStdString(longDesc).simplified();
|
2015-08-03 20:53:56 +00:00
|
|
|
} else if (role == AircraftPackageSizeRole) {
|
|
|
|
return static_cast<int>(item->fileSizeBytes());
|
|
|
|
} else if (role == AircraftURIRole) {
|
2016-11-16 21:27:00 +00:00
|
|
|
return QUrl("package:" + QString::fromStdString(item->qualifiedVariantId(state.variant)));
|
2015-08-03 20:53:56 +00:00
|
|
|
} else if (role == AircraftHasRatingsRole) {
|
|
|
|
return item->properties()->hasChild("rating");
|
|
|
|
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
2018-10-08 11:31:27 +00:00
|
|
|
return packageRating(item, role - AircraftRatingRole);
|
2017-06-22 09:45:47 +00:00
|
|
|
} else if (role == AircraftStatusRole) {
|
2017-10-09 20:53:26 +00:00
|
|
|
return QmlAircraftInfo::packageAircraftStatus(item);
|
2017-06-22 09:45:47 +00:00
|
|
|
} else if (role == AircraftMinVersionRole) {
|
|
|
|
const std::string v = item->properties()->getStringValue("minimum-fg-version");
|
|
|
|
if (!v.empty()) {
|
|
|
|
return QString::fromStdString(v);
|
|
|
|
}
|
2015-03-13 16:29:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return QVariant();
|
|
|
|
}
|
2015-03-10 00:13:55 +00:00
|
|
|
|
2018-10-08 11:31:27 +00:00
|
|
|
QVariant AircraftItemModel::packageRating(const PackageRef& p, int ratingIndex) const
|
|
|
|
{
|
|
|
|
return LocalAircraftCache::ratingFromProperties(p->properties()->getChild("rating"), ratingIndex);
|
|
|
|
}
|
|
|
|
|
2015-03-10 00:13:55 +00:00
|
|
|
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
|
|
{
|
2016-01-04 02:58:03 +00:00
|
|
|
int row = index.row();
|
2018-07-02 13:11:01 +00:00
|
|
|
quint32 newValue = value.toUInt();
|
2016-11-16 21:27:00 +00:00
|
|
|
|
2015-03-10 00:13:55 +00:00
|
|
|
if (role == AircraftVariantRole) {
|
2016-11-16 21:27:00 +00:00
|
|
|
if (m_delegateStates[row].variant == newValue) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_delegateStates[row].variant = newValue;
|
|
|
|
emit dataChanged(index, index);
|
|
|
|
return true;
|
2020-04-01 09:47:29 +00:00
|
|
|
} else if (role == AircraftIsFavouriteRole) {
|
|
|
|
const auto uri = data(index, AircraftURIRole).toUrl();
|
2020-04-04 08:20:23 +00:00
|
|
|
bool changed = FavouriteAircraftData::instance()->setFavourite(uri, value.toBool());
|
|
|
|
if (changed) {
|
|
|
|
emit dataChanged(index, index);
|
2020-04-01 09:47:29 +00:00
|
|
|
}
|
2016-11-16 21:27:00 +00:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:13:55 +00:00
|
|
|
return false;
|
2017-06-22 09:45:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QHash<int, QByteArray> AircraftItemModel::roleNames() const
|
|
|
|
{
|
|
|
|
QHash<int, QByteArray> result = QAbstractListModel::roleNames();
|
|
|
|
|
|
|
|
result[Qt::DisplayRole] = "title";
|
|
|
|
result[AircraftURIRole] = "uri";
|
|
|
|
result[AircraftPackageIdRole] = "package";
|
|
|
|
result[AircraftAuthorsRole] = "authors";
|
|
|
|
result[AircraftVariantCountRole] = "variantCount";
|
|
|
|
result[AircraftLongDescriptionRole] = "description";
|
|
|
|
result[AircraftPackageSizeRole] = "packageSizeBytes";
|
|
|
|
result[AircraftPackageStatusRole] = "packageStatus";
|
|
|
|
|
|
|
|
result[AircraftInstallDownloadedSizeRole] = "downloadedBytes";
|
|
|
|
result[AircraftVariantRole] = "activeVariant";
|
2020-04-01 09:47:29 +00:00
|
|
|
result[AircraftIsFavouriteRole] = "favourite";
|
2017-06-22 09:45:47 +00:00
|
|
|
|
|
|
|
result[AircraftStatusRole] = "aircraftStatus";
|
|
|
|
result[AircraftMinVersionRole] = "requiredFGVersion";
|
|
|
|
|
|
|
|
result[AircraftHasRatingsRole] = "hasRatings";
|
|
|
|
result[AircraftRatingRole] = "ratingFDM";
|
|
|
|
result[AircraftRatingRole + 1] = "ratingSystems";
|
|
|
|
result[AircraftRatingRole + 2] = "ratingCockpit";
|
|
|
|
result[AircraftRatingRole + 3] = "ratingExterior";
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2015-03-10 00:13:55 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
QModelIndex AircraftItemModel::indexOfAircraftURI(QUrl uri) const
|
2015-03-10 00:13:55 +00:00
|
|
|
{
|
2016-04-15 16:06:53 +00:00
|
|
|
if (uri.isEmpty()) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
if (uri.isLocalFile()) {
|
2017-10-09 20:53:26 +00:00
|
|
|
int row = LocalAircraftCache::instance()->findIndexWithUri(uri);
|
|
|
|
if (row >= 0) {
|
|
|
|
return index(row);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
|
|
|
} else if (uri.scheme() == "package") {
|
|
|
|
QString ident = uri.path();
|
2017-10-09 20:53:26 +00:00
|
|
|
int rowOffset = m_cachedLocalAircraftCount;
|
2016-04-15 16:06:53 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
PackageRef pkg = m_packageRoot->getPackageById(ident.toStdString());
|
|
|
|
if (pkg) {
|
2020-04-02 15:13:12 +00:00
|
|
|
const auto numPackages = m_packages.size();
|
|
|
|
for (unsigned int i=0; i < numPackages; ++i) {
|
|
|
|
if (m_packages.at(i) == pkg) {
|
|
|
|
return index(static_cast<int>(rowOffset + i));
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
|
|
|
} // of linear package scan
|
2015-03-10 00:13:55 +00:00
|
|
|
}
|
2016-04-14 14:41:19 +00:00
|
|
|
} else if (uri.scheme() == "") {
|
|
|
|
// Empty URI scheme (no selection), nothing to do
|
2015-08-03 20:53:56 +00:00
|
|
|
} else {
|
|
|
|
qWarning() << "Unknown aircraft URI scheme" << uri << uri.scheme();
|
2015-03-10 00:13:55 +00:00
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-03-10 00:13:55 +00:00
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
|
2016-11-18 16:10:02 +00:00
|
|
|
void AircraftItemModel::selectVariantForAircraftURI(QUrl uri)
|
|
|
|
{
|
|
|
|
if (uri.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int variantIndex = 0;
|
|
|
|
QModelIndex modelIndex;
|
|
|
|
|
|
|
|
if (uri.isLocalFile()) {
|
2017-10-09 20:53:26 +00:00
|
|
|
int row = LocalAircraftCache::instance()->findIndexWithUri(uri);
|
|
|
|
if (row < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2016-11-18 16:10:02 +00:00
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
modelIndex = index(row);
|
|
|
|
// now check if we are actually selecting a variant
|
|
|
|
const AircraftItemPtr item = LocalAircraftCache::instance()->itemAt(row);
|
|
|
|
|
|
|
|
const QString path = uri.toLocalFile();
|
|
|
|
for (int vr=0; vr < item->variants.size(); ++vr) {
|
|
|
|
if (item->variants.at(vr)->path == path) {
|
|
|
|
variantIndex = vr + 1;
|
|
|
|
break;
|
2016-11-18 16:10:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (uri.scheme() == "package") {
|
|
|
|
QString ident = uri.path();
|
2017-10-09 20:53:26 +00:00
|
|
|
int rowOffset = m_cachedLocalAircraftCount;
|
2016-11-18 16:10:02 +00:00
|
|
|
|
|
|
|
PackageRef pkg = m_packageRoot->getPackageById(ident.toStdString());
|
|
|
|
if (pkg) {
|
|
|
|
for (size_t i=0; i < m_packages.size(); ++i) {
|
|
|
|
if (m_packages[i] == pkg) {
|
2020-04-02 15:13:12 +00:00
|
|
|
modelIndex = index(rowOffset + static_cast<int>(i));
|
2016-11-18 16:10:02 +00:00
|
|
|
variantIndex = pkg->indexOfVariant(ident.toStdString());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} // of linear package scan
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qWarning() << "Unknown aircraft URI scheme" << uri << uri.scheme();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modelIndex.isValid()) {
|
|
|
|
setData(modelIndex, variantIndex, AircraftVariantRole);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-18 21:25:05 +00:00
|
|
|
QString AircraftItemModel::nameForAircraftURI(QUrl uri) const
|
|
|
|
{
|
|
|
|
if (uri.isLocalFile()) {
|
2017-10-09 20:53:26 +00:00
|
|
|
AircraftItemPtr item = LocalAircraftCache::instance()->findItemWithUri(uri);
|
2017-10-13 15:48:24 +00:00
|
|
|
if (!item) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
const QString path = uri.toLocalFile();
|
|
|
|
if (item->path == path) {
|
2020-06-19 09:45:47 +00:00
|
|
|
return item->name();
|
2017-10-09 20:53:26 +00:00
|
|
|
}
|
2016-12-18 21:25:05 +00:00
|
|
|
|
2017-10-09 20:53:26 +00:00
|
|
|
// check variants too
|
|
|
|
for (int vr=0; vr < item->variants.size(); ++vr) {
|
2017-12-08 22:03:09 +00:00
|
|
|
auto variant = item->variants.at(vr);
|
|
|
|
if (variant->path == path) {
|
2020-06-19 09:45:47 +00:00
|
|
|
return variant->name();
|
2016-12-18 21:25:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (uri.scheme() == "package") {
|
|
|
|
QString ident = uri.path();
|
|
|
|
PackageRef pkg = m_packageRoot->getPackageById(ident.toStdString());
|
|
|
|
if (pkg) {
|
2020-04-01 09:47:29 +00:00
|
|
|
const auto variantIndex = pkg->indexOfVariant(ident.toStdString());
|
2016-12-18 21:25:05 +00:00
|
|
|
return QString::fromStdString(pkg->nameForVariant(variantIndex));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qWarning() << "Unknown aircraft URI scheme" << uri << uri.scheme();
|
|
|
|
}
|
|
|
|
|
2017-10-13 15:48:24 +00:00
|
|
|
return {};
|
2016-12-18 21:25:05 +00:00
|
|
|
}
|
|
|
|
|
2018-01-07 14:19:28 +00:00
|
|
|
void AircraftItemModel::onScanAddedItems(int addedCount)
|
2015-03-10 00:13:55 +00:00
|
|
|
{
|
2020-04-01 09:47:29 +00:00
|
|
|
Q_UNUSED(addedCount)
|
2018-01-07 14:19:28 +00:00
|
|
|
const auto items = LocalAircraftCache::instance()->allItems();
|
|
|
|
const int newItemCount = items.size() - m_cachedLocalAircraftCount;
|
|
|
|
const int firstRow = m_cachedLocalAircraftCount;
|
|
|
|
const int lastRow = firstRow + newItemCount - 1;
|
2015-03-10 00:13:55 +00:00
|
|
|
|
|
|
|
beginInsertRows(QModelIndex(), firstRow, lastRow);
|
2018-01-07 14:19:28 +00:00
|
|
|
m_delegateStates.insert(m_cachedLocalAircraftCount, newItemCount, {});
|
|
|
|
m_cachedLocalAircraftCount += newItemCount;
|
2015-03-10 00:13:55 +00:00
|
|
|
endInsertRows();
|
2018-07-23 08:10:08 +00:00
|
|
|
emit contentsChanged();
|
2015-03-10 00:13:55 +00:00
|
|
|
}
|
|
|
|
|
2017-12-15 15:42:36 +00:00
|
|
|
void AircraftItemModel::onLocalCacheCleared()
|
|
|
|
{
|
2018-08-28 22:34:55 +00:00
|
|
|
if (m_cachedLocalAircraftCount > 0) {
|
|
|
|
const int firstRow = 0;
|
|
|
|
const int lastRow = m_cachedLocalAircraftCount - 1;
|
2017-12-15 15:42:36 +00:00
|
|
|
|
2018-08-28 22:34:55 +00:00
|
|
|
beginRemoveRows(QModelIndex(), firstRow, lastRow);
|
|
|
|
m_delegateStates.remove(0, m_cachedLocalAircraftCount);
|
|
|
|
m_cachedLocalAircraftCount = 0;
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
2017-12-15 15:42:36 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
void AircraftItemModel::installFailed(QModelIndex index, simgear::pkg::Delegate::StatusCode reason)
|
|
|
|
{
|
|
|
|
QString msg;
|
|
|
|
switch (reason) {
|
|
|
|
case Delegate::FAIL_CHECKSUM:
|
|
|
|
msg = tr("Invalid package checksum"); break;
|
|
|
|
case Delegate::FAIL_DOWNLOAD:
|
|
|
|
msg = tr("Download failed"); break;
|
|
|
|
case Delegate::FAIL_EXTRACT:
|
|
|
|
msg = tr("Package could not be extracted"); break;
|
|
|
|
case Delegate::FAIL_FILESYSTEM:
|
|
|
|
msg = tr("A local file-system error occurred"); break;
|
2015-09-28 00:44:29 +00:00
|
|
|
case Delegate::FAIL_NOT_FOUND:
|
|
|
|
msg = tr("Package file missing from download server"); break;
|
2015-08-03 20:53:56 +00:00
|
|
|
case Delegate::FAIL_UNKNOWN:
|
|
|
|
default:
|
|
|
|
msg = tr("Unknown reason");
|
|
|
|
}
|
2015-09-28 00:44:29 +00:00
|
|
|
|
|
|
|
emit aircraftInstallFailed(index, msg);
|
2015-08-03 20:53:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AircraftItemModel::installSucceeded(QModelIndex index)
|
|
|
|
{
|
|
|
|
emit aircraftInstallCompleted(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AircraftItemModel::isIndexRunnable(const QModelIndex& index) const
|
|
|
|
{
|
2017-10-09 20:53:26 +00:00
|
|
|
if (index.row() < m_cachedLocalAircraftCount) {
|
2015-08-03 20:53:56 +00:00
|
|
|
return true; // local file, always runnable
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2020-04-01 09:47:29 +00:00
|
|
|
quint32 packageIndex = static_cast<quint32>(index.row() - m_cachedLocalAircraftCount);
|
2015-08-03 20:53:56 +00:00
|
|
|
const PackageRef& pkg(m_packages[packageIndex]);
|
|
|
|
InstallRef ex = pkg->existingInstall();
|
|
|
|
if (!ex.valid()) {
|
|
|
|
return false; // not installed
|
|
|
|
}
|
2015-11-14 16:45:04 +00:00
|
|
|
|
2015-08-03 20:53:56 +00:00
|
|
|
return !ex->isDownloading();
|
|
|
|
}
|
|
|
|
|