Lots of work on aircraft package support
This commit is contained in:
parent
c2cbb36d16
commit
18a898f5f9
12 changed files with 621 additions and 137 deletions
|
@ -88,7 +88,7 @@ void AddCatalogDialog::updateUi()
|
||||||
"%2 aircraft are included in this hangar.").arg(catDesc).arg(m_result->packages().size());
|
"%2 aircraft are included in this hangar.").arg(catDesc).arg(m_result->packages().size());
|
||||||
ui->resultsSummaryLabel->setText(s);
|
ui->resultsSummaryLabel->setText(s);
|
||||||
} else if (m_state == STATE_DOWNLOAD_FAILED) {
|
} else if (m_state == STATE_DOWNLOAD_FAILED) {
|
||||||
Delegate::FailureCode code = m_result->status();
|
Delegate::StatusCode code = m_result->status();
|
||||||
qWarning() << Q_FUNC_INFO << "failed with code" << code;
|
qWarning() << Q_FUNC_INFO << "failed with code" << code;
|
||||||
QString s;
|
QString s;
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
@ -98,7 +98,7 @@ void AddCatalogDialog::updateUi()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Delegate::FAIL_VERSION:
|
case Delegate::FAIL_VERSION:
|
||||||
s = tr("The provided hangar is for a different version of FLightGear. "
|
s = tr("The provided hangar is for a different version of FlightGear. "
|
||||||
"(This is version %1)").arg(QString::fromUtf8(FLIGHTGEAR_VERSION));
|
"(This is version %1)").arg(QString::fromUtf8(FLIGHTGEAR_VERSION));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -152,14 +152,14 @@ void AddCatalogDialog::reject()
|
||||||
|
|
||||||
void AddCatalogDialog::onCatalogStatusChanged(Catalog* cat)
|
void AddCatalogDialog::onCatalogStatusChanged(Catalog* cat)
|
||||||
{
|
{
|
||||||
Delegate::FailureCode s = cat->status();
|
Delegate::StatusCode s = cat->status();
|
||||||
qDebug() << Q_FUNC_INFO << "cat status:" << s;
|
qDebug() << Q_FUNC_INFO << "cat status:" << s;
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case Delegate::CATALOG_REFRESHED:
|
case Delegate::STATUS_REFRESHED:
|
||||||
m_state = STATE_FINISHED;
|
m_state = STATE_FINISHED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Delegate::FAIL_IN_PROGRESS:
|
case Delegate::STATUS_IN_PROGRESS:
|
||||||
// don't jump to STATE_FINISHED
|
// don't jump to STATE_FINISHED
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -143,29 +143,79 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
|
||||||
|
|
||||||
QVariant v = index.data(AircraftPackageStatusRole);
|
QVariant v = index.data(AircraftPackageStatusRole);
|
||||||
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
|
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
|
||||||
// status = PackageNotInstalled;
|
double downloadFraction = 0.0;
|
||||||
|
|
||||||
if (status != PackageInstalled) {
|
if (status != PackageInstalled) {
|
||||||
|
QString buttonText, infoText;
|
||||||
|
QColor buttonColor(27, 122, 211);
|
||||||
|
|
||||||
|
double sizeInMBytes = index.data(AircraftPackageSizeRole).toInt();
|
||||||
|
sizeInMBytes /= 0x100000;
|
||||||
|
|
||||||
|
if (status == PackageDownloading) {
|
||||||
|
buttonText = tr("Cancel");
|
||||||
|
double downloadedMB = index.data(AircraftInstallDownloadedSizeRole).toInt();
|
||||||
|
downloadedMB /= 0x100000;
|
||||||
|
infoText = QStringLiteral("%1 MB of %2 MB").arg(downloadedMB, 0, 'f', 1).arg(sizeInMBytes, 0, 'f', 1);
|
||||||
|
buttonColor = QColor(0xcf, 0xcf, 0xcf);
|
||||||
|
downloadFraction = downloadedMB / sizeInMBytes;
|
||||||
|
} else if (status == PackageQueued) {
|
||||||
|
buttonText = tr("Cancel");
|
||||||
|
infoText = tr("Waiting to download %1 MB").arg(sizeInMBytes, 0, 'f', 1);
|
||||||
|
buttonColor = QColor(0xcf, 0xcf, 0xcf);
|
||||||
|
} else {
|
||||||
|
infoText = QStringLiteral("%1MB").arg(sizeInMBytes, 0, 'f', 1);
|
||||||
|
if (status == PackageNotInstalled) {
|
||||||
|
buttonText = "Install";
|
||||||
|
} else if (status == PackageUpdateAvailable) {
|
||||||
|
buttonText = "Update";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
painter->setBrush(Qt::NoBrush);
|
painter->setBrush(Qt::NoBrush);
|
||||||
QRect buttonRect = packageButtonRect(option.rect, index);
|
QRect buttonRect = packageButtonRect(option.rect, index);
|
||||||
painter->setPen(Qt::NoPen);
|
painter->setPen(Qt::NoPen);
|
||||||
painter->setBrush(QColor(27, 122, 211));
|
painter->setBrush(buttonColor);
|
||||||
painter->drawRoundedRect(buttonRect, 5, 5);
|
painter->drawRoundedRect(buttonRect, 5, 5);
|
||||||
painter->setPen(Qt::white);
|
painter->setPen(Qt::white);
|
||||||
|
painter->drawText(buttonRect, Qt::AlignCenter, buttonText);
|
||||||
|
|
||||||
|
QRect infoTextRect = buttonRect;
|
||||||
|
infoTextRect.setLeft(buttonRect.right() + MARGIN);
|
||||||
|
infoTextRect.setWidth(200);
|
||||||
|
|
||||||
|
if (status == PackageDownloading) {
|
||||||
|
QRect progressRect = infoTextRect;
|
||||||
|
progressRect.setHeight(6);
|
||||||
|
painter->setPen(QPen(QColor(0xcf, 0xcf, 0xcf), 0));
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->drawRoundedRect(progressRect, 3, 3);
|
||||||
|
infoTextRect.setTop(progressRect.bottom() + 1);
|
||||||
|
|
||||||
if (status == PackageNotInstalled) {
|
QRect progressBarRect = progressRect.marginsRemoved(QMargins(2, 2, 2, 2));
|
||||||
painter->drawText(buttonRect, Qt::AlignCenter, "Install");
|
|
||||||
} else if (status == PackageUpdateAvailable) {
|
progressBarRect.setWidth(static_cast<int>(progressBarRect.width() * downloadFraction));
|
||||||
painter->drawText(buttonRect, Qt::AlignCenter, "Update");
|
|
||||||
|
painter->setBrush(QColor(27, 122, 211));
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRoundedRect(progressBarRect, 2, 2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
painter->setPen(Qt::black);
|
||||||
|
painter->drawText(infoTextRect, Qt::AlignLeft | Qt::AlignVCenter, infoText);
|
||||||
|
} // of update / install / download status
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
|
QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||||
{
|
{
|
||||||
QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
|
QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
|
||||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
|
||||||
contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
|
|
||||||
|
|
||||||
|
const int THUMBNAIL_WIDTH = 172;
|
||||||
|
// don't request the thumbnail here for remote sources. Assume the default
|
||||||
|
//QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||||
|
//contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
|
||||||
|
contentRect.setLeft(contentRect.left() + MARGIN + THUMBNAIL_WIDTH);
|
||||||
|
|
||||||
QFont f;
|
QFont f;
|
||||||
f.setPointSize(18);
|
f.setPointSize(18);
|
||||||
QFontMetrics metrics(f);
|
QFontMetrics metrics(f);
|
||||||
|
@ -209,10 +259,10 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
|
||||||
QModelIndex index = m_view->indexAt( me->pos() );
|
QModelIndex index = m_view->indexAt( me->pos() );
|
||||||
int variantCount = index.data(AircraftVariantCountRole).toInt();
|
int variantCount = index.data(AircraftVariantCountRole).toInt();
|
||||||
int variantIndex = index.data(AircraftVariantRole).toInt();
|
int variantIndex = index.data(AircraftVariantRole).toInt();
|
||||||
|
QRect vr = m_view->visualRect(index);
|
||||||
|
|
||||||
if ( (event->type() == QEvent::MouseButtonRelease) && (variantCount > 0) )
|
if ( (event->type() == QEvent::MouseButtonRelease) && (variantCount > 0) )
|
||||||
{
|
{
|
||||||
QRect vr = m_view->visualRect(index);
|
|
||||||
QRect leftCycleRect = leftCycleArrowRect(vr, index),
|
QRect leftCycleRect = leftCycleArrowRect(vr, index),
|
||||||
rightCycleRect = rightCycleArrowRect(vr, index);
|
rightCycleRect = rightCycleArrowRect(vr, index);
|
||||||
|
|
||||||
|
@ -226,6 +276,22 @@ bool AircraftItemDelegate::eventFilter( QObject*, QEvent* event )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((event->type() == QEvent::MouseButtonRelease) &&
|
||||||
|
packageButtonRect(vr, index).contains(me->pos()))
|
||||||
|
{
|
||||||
|
QVariant v = index.data(AircraftPackageStatusRole);
|
||||||
|
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
|
||||||
|
if (status == PackageNotInstalled) {
|
||||||
|
emit requestInstall(index);
|
||||||
|
} else if ((status == PackageDownloading) || (status == PackageQueued)) {
|
||||||
|
emit cancelDownload(index);
|
||||||
|
} else if (status == PackageUpdateAvailable) {
|
||||||
|
emit requestInstall(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} else if ( event->type() == QEvent::MouseMove ) {
|
} else if ( event->type() == QEvent::MouseMove ) {
|
||||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||||
QModelIndex index = m_view->indexAt( me->pos() );
|
QModelIndex index = m_view->indexAt( me->pos() );
|
||||||
|
@ -273,7 +339,8 @@ QRect AircraftItemDelegate::packageButtonRect(const QRect& visualRect, const QMo
|
||||||
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||||
contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
|
contentRect.setLeft(contentRect.left() + MARGIN + thumbnail.width());
|
||||||
|
|
||||||
return QRect(contentRect.left() + ARROW_SIZE, contentRect.bottom() - 24, 60, BUTTON_HEIGHT);
|
return QRect(contentRect.left() + ARROW_SIZE, contentRect.bottom() - 24,
|
||||||
|
BUTTON_WIDTH, BUTTON_HEIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
|
void AircraftItemDelegate::drawRating(QPainter* painter, QString label, const QRect& box, int value) const
|
||||||
|
|
|
@ -32,7 +32,8 @@ public:
|
||||||
static const int MARGIN = 4;
|
static const int MARGIN = 4;
|
||||||
static const int ARROW_SIZE = 20;
|
static const int ARROW_SIZE = 20;
|
||||||
static const int BUTTON_HEIGHT = 24;
|
static const int BUTTON_HEIGHT = 24;
|
||||||
|
static const int BUTTON_WIDTH = 80;
|
||||||
|
|
||||||
AircraftItemDelegate(QListView* view);
|
AircraftItemDelegate(QListView* view);
|
||||||
|
|
||||||
virtual void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
|
virtual void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const;
|
||||||
|
@ -44,6 +45,9 @@ public:
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void variantChanged(const QModelIndex& index);
|
void variantChanged(const QModelIndex& index);
|
||||||
|
|
||||||
|
void requestInstall(const QModelIndex& index);
|
||||||
|
|
||||||
|
void cancelDownload(const QModelIndex& index);
|
||||||
private:
|
private:
|
||||||
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
QRect leftCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||||
QRect rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
QRect rightCycleArrowRect(const QRect& visualRect, const QModelIndex& index) const;
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
// Simgear
|
// Simgear
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
|
@ -39,6 +40,8 @@
|
||||||
// FlightGear
|
// FlightGear
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
|
|
||||||
|
const int STANDARD_THUMBNAIL_HEIGHT = 128;
|
||||||
|
|
||||||
using namespace simgear::pkg;
|
using namespace simgear::pkg;
|
||||||
|
|
||||||
AircraftItem::AircraftItem() :
|
AircraftItem::AircraftItem() :
|
||||||
|
@ -123,8 +126,8 @@ QPixmap AircraftItem::thumbnail() const
|
||||||
if (dir.exists("thumbnail.jpg")) {
|
if (dir.exists("thumbnail.jpg")) {
|
||||||
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
|
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
|
||||||
// resize to the standard size
|
// resize to the standard size
|
||||||
if (m_thumbnail.height() > 128) {
|
if (m_thumbnail.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||||
m_thumbnail = m_thumbnail.scaledToHeight(128);
|
m_thumbnail = m_thumbnail.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,9 +153,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** thread-safe access to items already scanned */
|
/** thread-safe access to items already scanned */
|
||||||
QList<AircraftItem*> items()
|
QVector<AircraftItemPtr> items()
|
||||||
{
|
{
|
||||||
QList<AircraftItem*> result;
|
QVector<AircraftItemPtr> result;
|
||||||
QMutexLocker g(&m_lock);
|
QMutexLocker g(&m_lock);
|
||||||
result.swap(m_items);
|
result.swap(m_items);
|
||||||
g.unlock();
|
g.unlock();
|
||||||
|
@ -196,13 +199,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<count; ++i) {
|
for (int i=0; i<count; ++i) {
|
||||||
AircraftItem* item = new AircraftItem;
|
AircraftItemPtr item(new AircraftItem);
|
||||||
item->fromDataStream(ds);
|
item->fromDataStream(ds);
|
||||||
|
|
||||||
QFileInfo finfo(item->path);
|
QFileInfo finfo(item->path);
|
||||||
if (!finfo.exists() || (finfo.lastModified() != item->pathModTime)) {
|
if (finfo.exists() && (finfo.lastModified() == item->pathModTime)) {
|
||||||
delete item;
|
|
||||||
} else {
|
|
||||||
// corresponding -set.xml file still exists and is
|
// corresponding -set.xml file still exists and is
|
||||||
// unmodified
|
// unmodified
|
||||||
m_cachedItems[item->path] = item;
|
m_cachedItems[item->path] = item;
|
||||||
|
@ -220,7 +221,7 @@ private:
|
||||||
quint32 count = m_nextCache.count();
|
quint32 count = m_nextCache.count();
|
||||||
ds << CACHE_VERSION << count;
|
ds << CACHE_VERSION << count;
|
||||||
|
|
||||||
Q_FOREACH(AircraftItem* item, m_nextCache.values()) {
|
Q_FOREACH(AircraftItemPtr item, m_nextCache.values()) {
|
||||||
item->toDataStream(ds);
|
item->toDataStream(ds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,18 +238,18 @@ private:
|
||||||
filters << "*-set.xml";
|
filters << "*-set.xml";
|
||||||
Q_FOREACH(QFileInfo child, path.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
Q_FOREACH(QFileInfo child, path.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
|
||||||
QDir childDir(child.absoluteFilePath());
|
QDir childDir(child.absoluteFilePath());
|
||||||
QMap<QString, AircraftItem*> baseAircraft;
|
QMap<QString, AircraftItemPtr> baseAircraft;
|
||||||
QList<AircraftItem*> variants;
|
QList<AircraftItemPtr> variants;
|
||||||
|
|
||||||
Q_FOREACH(QFileInfo xmlChild, childDir.entryInfoList(filters, QDir::Files)) {
|
Q_FOREACH(QFileInfo xmlChild, childDir.entryInfoList(filters, QDir::Files)) {
|
||||||
try {
|
try {
|
||||||
QString absolutePath = xmlChild.absoluteFilePath();
|
QString absolutePath = xmlChild.absoluteFilePath();
|
||||||
AircraftItem* item = NULL;
|
AircraftItemPtr item;
|
||||||
|
|
||||||
if (m_cachedItems.contains(absolutePath)) {
|
if (m_cachedItems.contains(absolutePath)) {
|
||||||
item = m_cachedItems.value(absolutePath);
|
item = m_cachedItems.value(absolutePath);
|
||||||
} else {
|
} else {
|
||||||
item = new AircraftItem(childDir, absolutePath);
|
item = AircraftItemPtr(new AircraftItem(childDir, absolutePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_nextCache[absolutePath] = item;
|
m_nextCache[absolutePath] = item;
|
||||||
|
@ -272,10 +273,9 @@ private:
|
||||||
} // of set.xml iteration
|
} // of set.xml iteration
|
||||||
|
|
||||||
// bind variants to their principals
|
// bind variants to their principals
|
||||||
Q_FOREACH(AircraftItem* item, variants) {
|
Q_FOREACH(AircraftItemPtr item, variants) {
|
||||||
if (!baseAircraft.contains(item->variantOf)) {
|
if (!baseAircraft.contains(item->variantOf)) {
|
||||||
qWarning() << "can't find principal aircraft " << item->variantOf << " for variant:" << item->path;
|
qWarning() << "can't find principal aircraft " << item->variantOf << " for variant:" << item->path;
|
||||||
delete item;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ private:
|
||||||
// lock mutex while we modify the items array
|
// lock mutex while we modify the items array
|
||||||
{
|
{
|
||||||
QMutexLocker g(&m_lock);
|
QMutexLocker g(&m_lock);
|
||||||
m_items.append(baseAircraft.values());
|
m_items.append(baseAircraft.values().toVector());
|
||||||
}
|
}
|
||||||
|
|
||||||
emit addedItems();
|
emit addedItems();
|
||||||
|
@ -294,19 +294,122 @@ private:
|
||||||
|
|
||||||
QMutex m_lock;
|
QMutex m_lock;
|
||||||
QStringList m_dirs;
|
QStringList m_dirs;
|
||||||
QList<AircraftItem*> m_items;
|
QVector<AircraftItemPtr> m_items;
|
||||||
|
|
||||||
QMap<QString, AircraftItem* > m_cachedItems;
|
QMap<QString, AircraftItemPtr > m_cachedItems;
|
||||||
QMap<QString, AircraftItem* > m_nextCache;
|
QMap<QString, AircraftItemPtr > m_nextCache;
|
||||||
|
|
||||||
bool m_done;
|
bool m_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PackageDelegate : public simgear::pkg::Delegate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PackageDelegate(AircraftItemModel* model) :
|
||||||
|
m_model(model)
|
||||||
|
{
|
||||||
|
m_model->m_packageRoot->addDelegate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PackageDelegate()
|
||||||
|
{
|
||||||
|
m_model->m_packageRoot->removeDelegate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void catalogRefreshed(CatalogRef aCatalog, StatusCode aReason)
|
||||||
|
{
|
||||||
|
if (aReason == STATUS_IN_PROGRESS) {
|
||||||
|
qDebug() << "doing refresh of" << QString::fromStdString(aCatalog->url());
|
||||||
|
} else if ((aReason == STATUS_REFRESHED) || (aReason == STATUS_SUCCESS)) {
|
||||||
|
m_model->refreshPackages();
|
||||||
|
} else {
|
||||||
|
qWarning() << "failed refresh of "
|
||||||
|
<< QString::fromStdString(aCatalog->url()) << ":" << aReason << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void startInstall(InstallRef aInstall)
|
||||||
|
{
|
||||||
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
||||||
|
m_model->dataChanged(mi, mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void installProgress(InstallRef aInstall, unsigned int bytes, unsigned int total)
|
||||||
|
{
|
||||||
|
Q_UNUSED(bytes);
|
||||||
|
Q_UNUSED(total);
|
||||||
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
||||||
|
m_model->dataChanged(mi, mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void finishInstall(InstallRef aInstall, StatusCode aReason)
|
||||||
|
{
|
||||||
|
QModelIndex mi(indexForPackage(aInstall->package()));
|
||||||
|
m_model->dataChanged(mi, mi);
|
||||||
|
|
||||||
|
if ((aReason != USER_CANCELLED) && (aReason != STATUS_SUCCESS)) {
|
||||||
|
m_model->installFailed(mi, aReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aReason == STATUS_SUCCESS) {
|
||||||
|
m_model->installSucceeded(mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dataForThumbnail(const std::string& aThumbnailUrl,
|
||||||
|
size_t length, const uint8_t* bytes)
|
||||||
|
{
|
||||||
|
QImage img = QImage::fromData(QByteArray::fromRawData(reinterpret_cast<const char*>(bytes), length));
|
||||||
|
if (img.isNull()) {
|
||||||
|
qWarning() << "failed to load image data for URL:" <<
|
||||||
|
QString::fromStdString(aThumbnailUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_model->m_thumbnailPixmapCache.insert(QString::fromStdString(aThumbnailUrl),
|
||||||
|
QPixmap::fromImage(img));
|
||||||
|
|
||||||
|
// notify any affected items. Linear scan here avoids another map/dict
|
||||||
|
// structure.
|
||||||
|
PackageList::const_iterator it;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (it=m_model->m_packages.begin(); it != m_model->m_packages.end(); ++it, ++i) {
|
||||||
|
const string_list& urls((*it)->thumbnailUrls());
|
||||||
|
string_list::const_iterator cit = std::find(urls.begin(), urls.end(), aThumbnailUrl);
|
||||||
|
if (cit != urls.end()) {
|
||||||
|
QModelIndex mi(m_model->index(i + m_model->m_items.size()));
|
||||||
|
m_model->dataChanged(mi, mi);
|
||||||
|
}
|
||||||
|
} // of packages iteration
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QModelIndex indexForPackage(const PackageRef& ref) const
|
||||||
|
{
|
||||||
|
PackageList::const_iterator it = std::find(m_model->m_packages.begin(),
|
||||||
|
m_model->m_packages.end(),
|
||||||
|
ref);
|
||||||
|
if (it == m_model->m_packages.end()) {
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = it - m_model->m_packages.begin();
|
||||||
|
return m_model->index(offset + m_model->m_items.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
AircraftItemModel* m_model;
|
||||||
|
};
|
||||||
|
|
||||||
AircraftItemModel::AircraftItemModel(QObject* pr, simgear::pkg::RootRef& rootRef) :
|
AircraftItemModel::AircraftItemModel(QObject* pr, simgear::pkg::RootRef& rootRef) :
|
||||||
QAbstractListModel(pr),
|
QAbstractListModel(pr),
|
||||||
m_scanThread(NULL),
|
m_scanThread(NULL),
|
||||||
m_packageRoot(rootRef)
|
m_packageRoot(rootRef)
|
||||||
{
|
{
|
||||||
|
new PackageDelegate(this);
|
||||||
|
// packages may already be refreshed, so pull now
|
||||||
|
refreshPackages();
|
||||||
}
|
}
|
||||||
|
|
||||||
AircraftItemModel::~AircraftItemModel()
|
AircraftItemModel::~AircraftItemModel()
|
||||||
|
@ -324,7 +427,6 @@ void AircraftItemModel::scanDirs()
|
||||||
abandonCurrentScan();
|
abandonCurrentScan();
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
qDeleteAll(m_items);
|
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
m_activeVariant.clear();
|
m_activeVariant.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
@ -345,7 +447,6 @@ void AircraftItemModel::scanDirs()
|
||||||
connect(m_scanThread, &AircraftScanThread::addedItems,
|
connect(m_scanThread, &AircraftScanThread::addedItems,
|
||||||
this, &AircraftItemModel::onScanResults);
|
this, &AircraftItemModel::onScanResults);
|
||||||
m_scanThread->start();
|
m_scanThread->start();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AircraftItemModel::abandonCurrentScan()
|
void AircraftItemModel::abandonCurrentScan()
|
||||||
|
@ -358,18 +459,51 @@ void AircraftItemModel::abandonCurrentScan()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
void AircraftItemModel::refreshPackages()
|
||||||
{
|
{
|
||||||
if (role == AircraftVariantRole) {
|
beginResetModel();
|
||||||
return m_activeVariant.at(index.row());
|
m_packages = m_packageRoot->allPackages();
|
||||||
}
|
m_packageVariant.resize(m_packages.size());
|
||||||
|
endResetModel();
|
||||||
const AircraftItem* item(m_items.at(index.row()));
|
|
||||||
quint32 variantIndex = m_activeVariant.at(index.row());
|
|
||||||
return dataFromItem(item, variantIndex, role);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant AircraftItemModel::dataFromItem(const AircraftItem* item, quint32 variantIndex, int role) const
|
int AircraftItemModel::rowCount(const QModelIndex& parent) const
|
||||||
|
{
|
||||||
|
return m_items.size() + m_packages.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (index.row() >= m_items.size()) {
|
||||||
|
quint32 packageIndex = index.row() - m_items.size();
|
||||||
|
|
||||||
|
if (role == AircraftVariantRole) {
|
||||||
|
return m_packageVariant.at(packageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PackageRef& pkg(m_packages[packageIndex]);
|
||||||
|
InstallRef ex = pkg->existingInstall();
|
||||||
|
|
||||||
|
if (role == AircraftInstallPercentRole) {
|
||||||
|
return ex.valid() ? ex->downloadedPercent() : 0;
|
||||||
|
} else if (role == AircraftInstallDownloadedSizeRole) {
|
||||||
|
return static_cast<quint64>(ex.valid() ? ex->downloadedBytes() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 variantIndex = m_packageVariant.at(packageIndex);
|
||||||
|
return dataFromPackage(pkg, variantIndex, role);
|
||||||
|
} else {
|
||||||
|
if (role == AircraftVariantRole) {
|
||||||
|
return m_activeVariant.at(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 variantIndex = m_activeVariant.at(index.row());
|
||||||
|
const AircraftItemPtr item(m_items.at(index.row()));
|
||||||
|
return dataFromItem(item, variantIndex, role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIndex, int role) const
|
||||||
{
|
{
|
||||||
if (role == AircraftVariantCountRole) {
|
if (role == AircraftVariantCountRole) {
|
||||||
return item->variants.count();
|
return item->variants.count();
|
||||||
|
@ -410,6 +544,8 @@ QVariant AircraftItemModel::dataFromItem(const AircraftItem* item, quint32 varia
|
||||||
return PackageInstalled; // always the case
|
return PackageInstalled; // always the case
|
||||||
} else if (role == Qt::ToolTipRole) {
|
} else if (role == Qt::ToolTipRole) {
|
||||||
return item->path;
|
return item->path;
|
||||||
|
} else if (role == AircraftURIRole) {
|
||||||
|
return QUrl::fromLocalFile(item->path);
|
||||||
} else if (role == AircraftHasRatingsRole) {
|
} else if (role == AircraftHasRatingsRole) {
|
||||||
bool have = false;
|
bool have = false;
|
||||||
for (int i=0; i<4; ++i) {
|
for (int i=0; i<4; ++i) {
|
||||||
|
@ -430,19 +566,28 @@ QVariant AircraftItemModel::dataFromItem(const AircraftItem* item, quint32 varia
|
||||||
|
|
||||||
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 variantIndex, int role) const
|
QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 variantIndex, int role) const
|
||||||
{
|
{
|
||||||
|
if (role == Qt::DecorationRole) {
|
||||||
|
role = AircraftThumbnailRole; // use first thumbnail
|
||||||
|
}
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return QString::fromStdString(item->name());
|
return QString::fromStdString(item->name());
|
||||||
} else if (role == AircraftPathRole) {
|
} else if (role == AircraftPathRole) {
|
||||||
// can we return the theoretical path?
|
InstallRef i = item->existingInstall();
|
||||||
|
if (i.valid()) {
|
||||||
|
return QString::fromStdString(i->primarySetPath().str());
|
||||||
|
}
|
||||||
} else if (role == AircraftPackageIdRole) {
|
} else if (role == AircraftPackageIdRole) {
|
||||||
return QString::fromStdString(item->id());
|
return QString::fromStdString(item->id());
|
||||||
} else if (role == AircraftPackageStatusRole) {
|
} else if (role == AircraftPackageStatusRole) {
|
||||||
bool installed = item->isInstalled();
|
InstallRef i = item->existingInstall();
|
||||||
if (installed) {
|
if (i.valid()) {
|
||||||
InstallRef i = item->existingInstall();
|
|
||||||
if (i->isDownloading()) {
|
if (i->isDownloading()) {
|
||||||
return PackageDownloading;
|
return PackageDownloading;
|
||||||
}
|
}
|
||||||
|
if (i->isQueued()) {
|
||||||
|
return PackageQueued;
|
||||||
|
}
|
||||||
if (i->hasUpdate()) {
|
if (i->hasUpdate()) {
|
||||||
return PackageUpdateAvailable;
|
return PackageUpdateAvailable;
|
||||||
}
|
}
|
||||||
|
@ -451,13 +596,72 @@ QVariant AircraftItemModel::dataFromPackage(const PackageRef& item, quint32 vari
|
||||||
} else {
|
} else {
|
||||||
return PackageNotInstalled;
|
return PackageNotInstalled;
|
||||||
}
|
}
|
||||||
|
} else if (role >= AircraftThumbnailRole) {
|
||||||
|
return packageThumbnail(item , role - AircraftThumbnailRole);
|
||||||
|
} else if (role == AircraftAuthorsRole) {
|
||||||
|
SGPropertyNode* authors = item->properties()->getChild("author");
|
||||||
|
if (authors) {
|
||||||
|
return QString::fromStdString(authors->getStringValue());
|
||||||
|
}
|
||||||
} else if (role == AircraftLongDescriptionRole) {
|
} else if (role == AircraftLongDescriptionRole) {
|
||||||
return QString::fromStdString(item->description());
|
return QString::fromStdString(item->description());
|
||||||
|
} else if (role == AircraftPackageSizeRole) {
|
||||||
|
return static_cast<int>(item->fileSizeBytes());
|
||||||
|
} else if (role == AircraftURIRole) {
|
||||||
|
return QUrl("package:" + QString::fromStdString(item->qualifiedId()));
|
||||||
|
} else if (role == AircraftHasRatingsRole) {
|
||||||
|
return item->properties()->hasChild("rating");
|
||||||
|
} else if ((role >= AircraftRatingRole) && (role < AircraftVariantDescriptionRole)) {
|
||||||
|
int ratingIndex = role - AircraftRatingRole;
|
||||||
|
SGPropertyNode* ratings = item->properties()->getChild("rating");
|
||||||
|
if (!ratings) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
return ratings->getChild(ratingIndex)->getIntValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant AircraftItemModel::packageThumbnail(PackageRef p, int index) const
|
||||||
|
{
|
||||||
|
const string_list& thumbnails(p->thumbnailUrls());
|
||||||
|
if (index >= thumbnails.size()) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string thumbnailUrl = thumbnails.at(index);
|
||||||
|
QString urlQString(QString::fromStdString(thumbnailUrl));
|
||||||
|
if (m_thumbnailPixmapCache.contains(urlQString)) {
|
||||||
|
// cache hit, easy
|
||||||
|
return m_thumbnailPixmapCache.value(urlQString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the on-disk store. This relies on the order of thumbnails in the
|
||||||
|
// results of thumbnailUrls and thumbnails corresponding
|
||||||
|
InstallRef ex = p->existingInstall();
|
||||||
|
if (ex.valid()) {
|
||||||
|
const string_list& thumbNames(p->thumbnails());
|
||||||
|
if (!thumbNames.empty()) {
|
||||||
|
SGPath path(ex->path());
|
||||||
|
path.append(p->thumbnails()[index]);
|
||||||
|
if (path.exists()) {
|
||||||
|
QPixmap pix;
|
||||||
|
pix.load(QString::fromStdString(path.str()));
|
||||||
|
// resize to the standard size
|
||||||
|
if (pix.height() > STANDARD_THUMBNAIL_HEIGHT) {
|
||||||
|
pix = pix.scaledToHeight(STANDARD_THUMBNAIL_HEIGHT);
|
||||||
|
}
|
||||||
|
m_thumbnailPixmapCache[urlQString] = pix;
|
||||||
|
return pix;
|
||||||
|
}
|
||||||
|
} // of have thumbnail file names
|
||||||
|
} // of have existing install
|
||||||
|
|
||||||
|
m_packageRoot->requestThumbnailData(thumbnailUrl);
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
{
|
{
|
||||||
if (role == AircraftVariantRole) {
|
if (role == AircraftVariantRole) {
|
||||||
|
@ -469,21 +673,36 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex AircraftItemModel::indexOfAircraftPath(QString path) const
|
QModelIndex AircraftItemModel::indexOfAircraftURI(QUrl uri) const
|
||||||
{
|
{
|
||||||
for (int row=0; row <m_items.size(); ++row) {
|
if (uri.isLocalFile()) {
|
||||||
const AircraftItem* item(m_items.at(row));
|
QString path = uri.toLocalFile();
|
||||||
if (item->path == path) {
|
for (int row=0; row <m_items.size(); ++row) {
|
||||||
return index(row);
|
const AircraftItemPtr item(m_items.at(row));
|
||||||
|
if (item->path == path) {
|
||||||
|
return index(row);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (uri.scheme() == "package") {
|
||||||
|
QString ident = uri.path();
|
||||||
|
PackageRef pkg = m_packageRoot->getPackageById(ident.toStdString());
|
||||||
|
if (pkg) {
|
||||||
|
for (int i=0; i < m_packages.size(); ++i) {
|
||||||
|
if (m_packages[i] == pkg) {
|
||||||
|
return index(m_items.size() + i);
|
||||||
|
}
|
||||||
|
} // of linear package scan
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qWarning() << "Unknown aircraft URI scheme" << uri << uri.scheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AircraftItemModel::onScanResults()
|
void AircraftItemModel::onScanResults()
|
||||||
{
|
{
|
||||||
QList<AircraftItem*> newItems = m_scanThread->items();
|
QVector<AircraftItemPtr> newItems = m_scanThread->items();
|
||||||
if (newItems.isEmpty())
|
if (newItems.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -505,4 +724,51 @@ void AircraftItemModel::onScanFinished()
|
||||||
m_scanThread = NULL;
|
m_scanThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AircraftItemModel::installFailed(QModelIndex index, simgear::pkg::Delegate::StatusCode reason)
|
||||||
|
{
|
||||||
|
Q_ASSERT(index.row() >= m_items.size());
|
||||||
|
|
||||||
|
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;
|
||||||
|
case Delegate::FAIL_UNKNOWN:
|
||||||
|
default:
|
||||||
|
msg = tr("Unknown reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 packageIndex = index.row() - m_items.size();
|
||||||
|
const PackageRef& pkg(m_packages[packageIndex]);
|
||||||
|
QString packageName = QString::fromStdString(pkg->description());
|
||||||
|
emit aircraftInstallFailed(index, tr("Failed installation of package '%1': %2").arg(packageName).arg(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AircraftItemModel::installSucceeded(QModelIndex index)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << index;
|
||||||
|
emit aircraftInstallCompleted(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AircraftItemModel::isIndexRunnable(const QModelIndex& index) const
|
||||||
|
{
|
||||||
|
if (index.row() < m_items.size()) {
|
||||||
|
return true; // local file, always runnable
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 packageIndex = index.row() - m_items.size();
|
||||||
|
const PackageRef& pkg(m_packages[packageIndex]);
|
||||||
|
InstallRef ex = pkg->existingInstall();
|
||||||
|
if (!ex.valid()) {
|
||||||
|
return false; // not installed
|
||||||
|
}
|
||||||
|
|
||||||
|
return !ex->isDownloading();
|
||||||
|
}
|
||||||
|
|
||||||
#include "AircraftModel.moc"
|
#include "AircraftModel.moc"
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
#include <simgear/package/Root.hxx>
|
#include <simgear/package/Root.hxx>
|
||||||
|
|
||||||
|
@ -39,6 +41,10 @@ const int AircraftPackageStatusRole = Qt::UserRole + 7;
|
||||||
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
const int AircraftPackageProgressRole = Qt::UserRole + 8;
|
||||||
const int AircraftLongDescriptionRole = Qt::UserRole + 9;
|
const int AircraftLongDescriptionRole = Qt::UserRole + 9;
|
||||||
const int AircraftHasRatingsRole = Qt::UserRole + 10;
|
const int AircraftHasRatingsRole = Qt::UserRole + 10;
|
||||||
|
const int AircraftInstallPercentRole = Qt::UserRole + 11;
|
||||||
|
const int AircraftPackageSizeRole = Qt::UserRole + 12;
|
||||||
|
const int AircraftInstallDownloadedSizeRole = Qt::UserRole + 13;
|
||||||
|
const int AircraftURIRole = Qt::UserRole + 14;
|
||||||
|
|
||||||
const int AircraftRatingRole = Qt::UserRole + 100;
|
const int AircraftRatingRole = Qt::UserRole + 100;
|
||||||
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
const int AircraftVariantDescriptionRole = Qt::UserRole + 200;
|
||||||
|
@ -47,6 +53,9 @@ const int AircraftThumbnailRole = Qt::UserRole + 300;
|
||||||
class AircraftScanThread;
|
class AircraftScanThread;
|
||||||
class QDataStream;
|
class QDataStream;
|
||||||
|
|
||||||
|
struct AircraftItem;
|
||||||
|
typedef QSharedPointer<AircraftItem> AircraftItemPtr;
|
||||||
|
|
||||||
struct AircraftItem
|
struct AircraftItem
|
||||||
{
|
{
|
||||||
AircraftItem();
|
AircraftItem();
|
||||||
|
@ -70,7 +79,7 @@ struct AircraftItem
|
||||||
QString variantOf;
|
QString variantOf;
|
||||||
QDateTime pathModTime;
|
QDateTime pathModTime;
|
||||||
|
|
||||||
QList<AircraftItem*> variants;
|
QList<AircraftItemPtr> variants;
|
||||||
private:
|
private:
|
||||||
mutable QPixmap m_thumbnail;
|
mutable QPixmap m_thumbnail;
|
||||||
};
|
};
|
||||||
|
@ -80,6 +89,7 @@ enum AircraftItemStatus {
|
||||||
PackageNotInstalled,
|
PackageNotInstalled,
|
||||||
PackageInstalled,
|
PackageInstalled,
|
||||||
PackageUpdateAvailable,
|
PackageUpdateAvailable,
|
||||||
|
PackageQueued,
|
||||||
PackageDownloading
|
PackageDownloading
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,11 +105,8 @@ public:
|
||||||
|
|
||||||
void scanDirs();
|
void scanDirs();
|
||||||
|
|
||||||
virtual int rowCount(const QModelIndex& parent) const
|
virtual int rowCount(const QModelIndex& parent) const;
|
||||||
{
|
|
||||||
return m_items.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex& index, int role) const;
|
virtual QVariant data(const QModelIndex& index, int role) const;
|
||||||
|
|
||||||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
|
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||||
|
@ -108,26 +115,53 @@ public:
|
||||||
* given a -set.xml path, return the corresponding model index, if one
|
* given a -set.xml path, return the corresponding model index, if one
|
||||||
* exists.
|
* exists.
|
||||||
*/
|
*/
|
||||||
QModelIndex indexOfAircraftPath(QString path) const;
|
// QModelIndex indexOfAircraftPath(QString path) const;
|
||||||
|
|
||||||
|
QModelIndex indexOfAircraftURI(QUrl uri) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return if a given aircraft is ready to be run, or not. Aircraft which
|
||||||
|
* are not installed, or are downloading, are not runnable.
|
||||||
|
*/
|
||||||
|
bool isIndexRunnable(const QModelIndex& index) const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void aircraftInstallFailed(QModelIndex index, QString errorMessage);
|
||||||
|
|
||||||
|
void aircraftInstallCompleted(QModelIndex index);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onScanResults();
|
void onScanResults();
|
||||||
|
|
||||||
void onScanFinished();
|
void onScanFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVariant dataFromItem(const AircraftItem* item, quint32 variantIndex, int role) const;
|
friend class PackageDelegate;
|
||||||
|
|
||||||
|
QVariant dataFromItem(AircraftItemPtr item, quint32 variantIndex, int role) const;
|
||||||
|
|
||||||
QVariant dataFromPackage(const simgear::pkg::PackageRef& item,
|
QVariant dataFromPackage(const simgear::pkg::PackageRef& item,
|
||||||
quint32 variantIndex, int role) const;
|
quint32 variantIndex, int role) const;
|
||||||
|
|
||||||
|
QVariant packageThumbnail(simgear::pkg::PackageRef p, int index) const;
|
||||||
|
|
||||||
void abandonCurrentScan();
|
void abandonCurrentScan();
|
||||||
|
void refreshPackages();
|
||||||
|
|
||||||
|
void installSucceeded(QModelIndex index);
|
||||||
|
void installFailed(QModelIndex index, simgear::pkg::Delegate::StatusCode reason);
|
||||||
|
|
||||||
QStringList m_paths;
|
QStringList m_paths;
|
||||||
AircraftScanThread* m_scanThread;
|
AircraftScanThread* m_scanThread;
|
||||||
QList<AircraftItem*> m_items;
|
QVector<AircraftItemPtr> m_items;
|
||||||
QList<quint32> m_activeVariant;
|
|
||||||
|
QVector<quint32> m_activeVariant;
|
||||||
|
QVector<quint32> m_packageVariant;
|
||||||
|
|
||||||
simgear::pkg::RootRef m_packageRoot;
|
simgear::pkg::RootRef m_packageRoot;
|
||||||
|
simgear::pkg::PackageList m_packages;
|
||||||
|
|
||||||
|
mutable QHash<QString, QPixmap> m_thumbnailPixmapCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // of FG_GUI_AIRCRAFT_MODEL
|
#endif // of FG_GUI_AIRCRAFT_MODEL
|
||||||
|
|
|
@ -59,7 +59,7 @@ QVariant CatalogListModel::data(const QModelIndex& index, int role) const
|
||||||
simgear::pkg::CatalogRef cat = m_packageRoot->catalogs().at(index.row());
|
simgear::pkg::CatalogRef cat = m_packageRoot->catalogs().at(index.row());
|
||||||
|
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return QString::fromStdString(cat->description());
|
return QString::fromStdString(cat->description()).trimmed();
|
||||||
} else if (role == Qt::ToolTipRole) {
|
} else if (role == Qt::ToolTipRole) {
|
||||||
return QString::fromStdString(cat->url());
|
return QString::fromStdString(cat->url());
|
||||||
} else if (role == CatalogUrlRole) {
|
} else if (role == CatalogUrlRole) {
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "CatalogListModel.hxx"
|
#include "CatalogListModel.hxx"
|
||||||
#include "AddCatalogDialog.hxx"
|
#include "AddCatalogDialog.hxx"
|
||||||
|
@ -128,7 +129,17 @@ void PathsDialog::onAddCatalog()
|
||||||
|
|
||||||
void PathsDialog::onRemoveCatalog()
|
void PathsDialog::onRemoveCatalog()
|
||||||
{
|
{
|
||||||
|
QModelIndex mi = m_ui->catalogsList->currentIndex();
|
||||||
|
if (mi.isValid()) {
|
||||||
|
QMessageBox mb;
|
||||||
|
mb.setText(QStringLiteral("Remove aircraft hangar '%1'?").arg(mi.data(Qt::DisplayRole).toString()));
|
||||||
|
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
|
mb.setDefaultButton(QMessageBox::No);
|
||||||
|
mb.exec();
|
||||||
|
|
||||||
|
QString pkgId = mi.data(CatalogIdRole).toString();
|
||||||
|
m_packageRoot->removeCatalogById(pkgId.toStdString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PathsDialog::onChangeDownloadDir()
|
void PathsDialog::onChangeDownloadDir()
|
||||||
|
|
|
@ -48,6 +48,9 @@
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/structure/subsystem_mgr.hxx>
|
#include <simgear/structure/subsystem_mgr.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
#include <simgear/package/Catalog.hxx>
|
||||||
|
#include <simgear/package/Package.hxx>
|
||||||
|
#include <simgear/package/Install.hxx>
|
||||||
|
|
||||||
#include "ui_Launcher.h"
|
#include "ui_Launcher.h"
|
||||||
#include "EditRatingsFilterDialog.hxx"
|
#include "EditRatingsFilterDialog.hxx"
|
||||||
|
@ -65,6 +68,7 @@
|
||||||
#include <Network/HTTPClient.hxx>
|
#include <Network/HTTPClient.hxx>
|
||||||
|
|
||||||
using namespace flightgear;
|
using namespace flightgear;
|
||||||
|
using namespace simgear::pkg;
|
||||||
|
|
||||||
const int MAX_RECENT_AIRPORTS = 32;
|
const int MAX_RECENT_AIRPORTS = 32;
|
||||||
const int MAX_RECENT_AIRCRAFT = 20;
|
const int MAX_RECENT_AIRCRAFT = 20;
|
||||||
|
@ -457,8 +461,6 @@ QtLauncher::QtLauncher() :
|
||||||
connect(m_ui->aircraftHistory, &QPushButton::clicked,
|
connect(m_ui->aircraftHistory, &QPushButton::clicked,
|
||||||
this, &QtLauncher::onPopupAircraftHistory);
|
this, &QtLauncher::onPopupAircraftHistory);
|
||||||
|
|
||||||
restoreSettings();
|
|
||||||
|
|
||||||
QAction* qa = new QAction(this);
|
QAction* qa = new QAction(this);
|
||||||
qa->setShortcut(QKeySequence("Ctrl+Q"));
|
qa->setShortcut(QKeySequence("Ctrl+Q"));
|
||||||
connect(qa, &QAction::triggered, this, &QtLauncher::onQuit);
|
connect(qa, &QAction::triggered, this, &QtLauncher::onQuit);
|
||||||
|
@ -495,7 +497,7 @@ QtLauncher::QtLauncher() :
|
||||||
updateSettingsSummary();
|
updateSettingsSummary();
|
||||||
|
|
||||||
fgInitPackageRoot();
|
fgInitPackageRoot();
|
||||||
simgear::pkg::RootRef r(globals->packageRoot());
|
RootRef r(globals->packageRoot());
|
||||||
|
|
||||||
FGHTTPClient* http = new FGHTTPClient;
|
FGHTTPClient* http = new FGHTTPClient;
|
||||||
globals->add_subsystem("http", http);
|
globals->add_subsystem("http", http);
|
||||||
|
@ -521,10 +523,21 @@ QtLauncher::QtLauncher() :
|
||||||
this, &QtLauncher::onAircraftSelected);
|
this, &QtLauncher::onAircraftSelected);
|
||||||
connect(delegate, &AircraftItemDelegate::variantChanged,
|
connect(delegate, &AircraftItemDelegate::variantChanged,
|
||||||
this, &QtLauncher::onAircraftSelected);
|
this, &QtLauncher::onAircraftSelected);
|
||||||
|
connect(delegate, &AircraftItemDelegate::requestInstall,
|
||||||
|
this, &QtLauncher::onRequestPackageInstall);
|
||||||
|
connect(delegate, &AircraftItemDelegate::cancelDownload,
|
||||||
|
this, &QtLauncher::onCancelDownload);
|
||||||
|
|
||||||
|
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallCompleted,
|
||||||
|
this, &QtLauncher::onAircraftInstalledCompleted);
|
||||||
|
connect(m_aircraftModel, &AircraftItemModel::aircraftInstallFailed,
|
||||||
|
this, &QtLauncher::onAircraftInstallFailed);
|
||||||
|
|
||||||
connect(m_ui->pathsButton, &QPushButton::clicked,
|
connect(m_ui->pathsButton, &QPushButton::clicked,
|
||||||
this, &QtLauncher::onEditPaths);
|
this, &QtLauncher::onEditPaths);
|
||||||
|
|
||||||
|
restoreSettings();
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
|
||||||
m_aircraftModel->scanDirs();
|
m_aircraftModel->scanDirs();
|
||||||
|
@ -566,6 +579,7 @@ void QtLauncher::initApp(int& argc, char** argv)
|
||||||
|
|
||||||
bool QtLauncher::runLauncherDialog()
|
bool QtLauncher::runLauncherDialog()
|
||||||
{
|
{
|
||||||
|
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||||
Q_INIT_RESOURCE(resources);
|
Q_INIT_RESOURCE(resources);
|
||||||
|
|
||||||
// startup the nav-cache now. This pre-empts normal startup of
|
// startup the nav-cache now. This pre-empts normal startup of
|
||||||
|
@ -598,7 +612,7 @@ void QtLauncher::restoreSettings()
|
||||||
m_ui->seasonCombo->setCurrentIndex(settings.value("season", 0).toInt());
|
m_ui->seasonCombo->setCurrentIndex(settings.value("season", 0).toInt());
|
||||||
|
|
||||||
// full paths to -set.xml files
|
// full paths to -set.xml files
|
||||||
m_recentAircraft = settings.value("recent-aircraft").toStringList();
|
m_recentAircraft = QUrl::fromStringList(settings.value("recent-aircraft").toStringList());
|
||||||
|
|
||||||
if (!m_recentAircraft.empty()) {
|
if (!m_recentAircraft.empty()) {
|
||||||
m_selectedAircraft = m_recentAircraft.front();
|
m_selectedAircraft = m_recentAircraft.front();
|
||||||
|
@ -638,7 +652,7 @@ void QtLauncher::saveSettings()
|
||||||
settings.setValue("enable-realwx", m_ui->fetchRealWxrCheckbox->isChecked());
|
settings.setValue("enable-realwx", m_ui->fetchRealWxrCheckbox->isChecked());
|
||||||
settings.setValue("start-paused", m_ui->startPausedCheck->isChecked());
|
settings.setValue("start-paused", m_ui->startPausedCheck->isChecked());
|
||||||
settings.setValue("ratings-filter", m_ui->ratingsFilterCheck->isChecked());
|
settings.setValue("ratings-filter", m_ui->ratingsFilterCheck->isChecked());
|
||||||
settings.setValue("recent-aircraft", m_recentAircraft);
|
settings.setValue("recent-aircraft", QUrl::toStringList(m_recentAircraft));
|
||||||
settings.setValue("recent-airports", m_recentAirports);
|
settings.setValue("recent-airports", m_recentAirports);
|
||||||
settings.setValue("timeofday", m_ui->timeOfDayCombo->currentIndex());
|
settings.setValue("timeofday", m_ui->timeOfDayCombo->currentIndex());
|
||||||
settings.setValue("season", m_ui->seasonCombo->currentIndex());
|
settings.setValue("season", m_ui->seasonCombo->currentIndex());
|
||||||
|
@ -679,13 +693,22 @@ void QtLauncher::onRun()
|
||||||
|
|
||||||
// aircraft
|
// aircraft
|
||||||
if (!m_selectedAircraft.isEmpty()) {
|
if (!m_selectedAircraft.isEmpty()) {
|
||||||
QFileInfo setFileInfo(m_selectedAircraft);
|
if (m_selectedAircraft.isLocalFile()) {
|
||||||
opt->addOption("aircraft-dir", setFileInfo.dir().absolutePath().toStdString());
|
QFileInfo setFileInfo(m_selectedAircraft.toLocalFile());
|
||||||
QString setFile = setFileInfo.fileName();
|
opt->addOption("aircraft-dir", setFileInfo.dir().absolutePath().toStdString());
|
||||||
Q_ASSERT(setFile.endsWith("-set.xml"));
|
QString setFile = setFileInfo.fileName();
|
||||||
setFile.truncate(setFile.count() - 8); // drop the '-set.xml' portion
|
Q_ASSERT(setFile.endsWith("-set.xml"));
|
||||||
opt->addOption("aircraft", setFile.toStdString());
|
setFile.truncate(setFile.count() - 8); // drop the '-set.xml' portion
|
||||||
|
opt->addOption("aircraft", setFile.toStdString());
|
||||||
|
} else if (m_selectedAircraft.scheme() == "package") {
|
||||||
|
PackageRef pkg = packageForAircraftURI(m_selectedAircraft);
|
||||||
|
// no need to set aircraft-dir, handled by the corresponding code
|
||||||
|
// in fgInitAircraft
|
||||||
|
opt->addOption("aircraft", pkg->qualifiedId());
|
||||||
|
} else {
|
||||||
|
qWarning() << "unsupported aircraft launch URL" << m_selectedAircraft;
|
||||||
|
}
|
||||||
|
|
||||||
// manage aircraft history
|
// manage aircraft history
|
||||||
if (m_recentAircraft.contains(m_selectedAircraft))
|
if (m_recentAircraft.contains(m_selectedAircraft))
|
||||||
m_recentAircraft.removeOne(m_selectedAircraft);
|
m_recentAircraft.removeOne(m_selectedAircraft);
|
||||||
|
@ -902,6 +925,29 @@ void QtLauncher::onToggleTerrasync(bool enabled)
|
||||||
} // of is enabled
|
} // of is enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtLauncher::onAircraftInstalledCompleted(QModelIndex index)
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO;
|
||||||
|
QUrl u = index.data(AircraftURIRole).toUrl();
|
||||||
|
if (u == m_selectedAircraft) {
|
||||||
|
// potentially enable the run button now!
|
||||||
|
updateSelectedAircraft();
|
||||||
|
qDebug() << "updating selected aircraft" << index.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtLauncher::onAircraftInstallFailed(QModelIndex index, QString errorMessage)
|
||||||
|
{
|
||||||
|
qWarning() << Q_FUNC_INFO << index.data(AircraftURIRole) << errorMessage;
|
||||||
|
|
||||||
|
QMessageBox msg;
|
||||||
|
msg.setWindowTitle(tr("Aircraft insallation failed"));
|
||||||
|
msg.setText(tr("An error occurred installing the aircraft %1: %2").
|
||||||
|
arg(index.data(Qt::DisplayRole).toString()).arg(errorMessage));
|
||||||
|
msg.addButton(QMessageBox::Ok);
|
||||||
|
msg.exec();
|
||||||
|
}
|
||||||
|
|
||||||
void QtLauncher::updateAirportDescription()
|
void QtLauncher::updateAirportDescription()
|
||||||
{
|
{
|
||||||
if (!m_selectedAirport) {
|
if (!m_selectedAirport) {
|
||||||
|
@ -944,20 +990,42 @@ void QtLauncher::onAirportChoiceSelected(const QModelIndex& index)
|
||||||
|
|
||||||
void QtLauncher::onAircraftSelected(const QModelIndex& index)
|
void QtLauncher::onAircraftSelected(const QModelIndex& index)
|
||||||
{
|
{
|
||||||
m_selectedAircraft = index.data(AircraftPathRole).toString();
|
m_selectedAircraft = index.data(AircraftURIRole).toUrl();
|
||||||
updateSelectedAircraft();
|
updateSelectedAircraft();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QtLauncher::onRequestPackageInstall(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
QString pkg = index.data(AircraftPackageIdRole).toString();
|
||||||
|
qDebug() << "request install of" << pkg;
|
||||||
|
simgear::pkg::PackageRef pref = globals->packageRoot()->getPackageById(pkg.toStdString());
|
||||||
|
pref->install();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QtLauncher::onCancelDownload(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
QString pkg = index.data(AircraftPackageIdRole).toString();
|
||||||
|
qDebug() << "cancel download of" << pkg;
|
||||||
|
simgear::pkg::PackageRef pref = globals->packageRoot()->getPackageById(pkg.toStdString());
|
||||||
|
simgear::pkg::InstallRef i = pref->existingInstall();
|
||||||
|
i->cancelDownload();
|
||||||
|
}
|
||||||
|
|
||||||
void QtLauncher::updateSelectedAircraft()
|
void QtLauncher::updateSelectedAircraft()
|
||||||
{
|
{
|
||||||
try {
|
QModelIndex index = m_aircraftModel->indexOfAircraftURI(m_selectedAircraft);
|
||||||
QFileInfo info(m_selectedAircraft);
|
if (index.isValid()) {
|
||||||
AircraftItem item(info.dir(), m_selectedAircraft);
|
QPixmap pm = index.data(Qt::DecorationRole).value<QPixmap>();
|
||||||
m_ui->thumbnail->setPixmap(item.thumbnail());
|
m_ui->thumbnail->setPixmap(pm);
|
||||||
m_ui->aircraftDescription->setText(item.description);
|
m_ui->aircraftDescription->setText(index.data(Qt::DisplayRole).toString());
|
||||||
} catch (sg_exception& e) {
|
|
||||||
|
int status = index.data(AircraftPackageStatusRole).toInt();
|
||||||
|
bool canRun = (status == PackageInstalled);
|
||||||
|
m_ui->runButton->setEnabled(canRun);
|
||||||
|
} else {
|
||||||
m_ui->thumbnail->setPixmap(QPixmap());
|
m_ui->thumbnail->setPixmap(QPixmap());
|
||||||
m_ui->aircraftDescription->setText("");
|
m_ui->aircraftDescription->setText("");
|
||||||
|
m_ui->runButton->setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,16 +1053,16 @@ void QtLauncher::onPopupAirportHistory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex QtLauncher::proxyIndexForAircraftPath(QString path) const
|
QModelIndex QtLauncher::proxyIndexForAircraftURI(QUrl uri) const
|
||||||
{
|
{
|
||||||
return m_aircraftProxy->mapFromSource(sourceIndexForAircraftPath(path));
|
return m_aircraftProxy->mapFromSource(sourceIndexForAircraftURI(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex QtLauncher::sourceIndexForAircraftPath(QString path) const
|
QModelIndex QtLauncher::sourceIndexForAircraftURI(QUrl uri) const
|
||||||
{
|
{
|
||||||
AircraftItemModel* sourceModel = qobject_cast<AircraftItemModel*>(m_aircraftProxy->sourceModel());
|
AircraftItemModel* sourceModel = qobject_cast<AircraftItemModel*>(m_aircraftProxy->sourceModel());
|
||||||
Q_ASSERT(sourceModel);
|
Q_ASSERT(sourceModel);
|
||||||
return sourceModel->indexOfAircraftPath(path);
|
return sourceModel->indexOfAircraftURI(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtLauncher::onPopupAircraftHistory()
|
void QtLauncher::onPopupAircraftHistory()
|
||||||
|
@ -1004,21 +1072,21 @@ void QtLauncher::onPopupAircraftHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu m;
|
QMenu m;
|
||||||
Q_FOREACH(QString path, m_recentAircraft) {
|
Q_FOREACH(QUrl uri, m_recentAircraft) {
|
||||||
QModelIndex index = sourceIndexForAircraftPath(path);
|
QModelIndex index = sourceIndexForAircraftURI(uri);
|
||||||
if (!index.isValid()) {
|
if (!index.isValid()) {
|
||||||
// not scanned yet
|
// not scanned yet
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QAction* act = m.addAction(index.data(Qt::DisplayRole).toString());
|
QAction* act = m.addAction(index.data(Qt::DisplayRole).toString());
|
||||||
act->setData(path);
|
act->setData(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPoint popupPos = m_ui->aircraftHistory->mapToGlobal(m_ui->aircraftHistory->rect().bottomLeft());
|
QPoint popupPos = m_ui->aircraftHistory->mapToGlobal(m_ui->aircraftHistory->rect().bottomLeft());
|
||||||
QAction* triggered = m.exec(popupPos);
|
QAction* triggered = m.exec(popupPos);
|
||||||
if (triggered) {
|
if (triggered) {
|
||||||
m_selectedAircraft = triggered->data().toString();
|
m_selectedAircraft = triggered->data().toUrl();
|
||||||
QModelIndex index = proxyIndexForAircraftPath(m_selectedAircraft);
|
QModelIndex index = proxyIndexForAircraftURI(m_selectedAircraft);
|
||||||
m_ui->aircraftList->selectionModel()->setCurrentIndex(index,
|
m_ui->aircraftList->selectionModel()->setCurrentIndex(index,
|
||||||
QItemSelectionModel::ClearAndSelect);
|
QItemSelectionModel::ClearAndSelect);
|
||||||
m_ui->aircraftFilter->clear();
|
m_ui->aircraftFilter->clear();
|
||||||
|
@ -1129,5 +1197,17 @@ void QtLauncher::onEditPaths()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
simgear::pkg::PackageRef QtLauncher::packageForAircraftURI(QUrl uri) const
|
||||||
|
{
|
||||||
|
if (uri.scheme() != "package") {
|
||||||
|
qWarning() << "invalid URL scheme:" << uri;
|
||||||
|
return simgear::pkg::PackageRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ident = uri.path();
|
||||||
|
qDebug() << Q_FUNC_INFO << uri << ident;
|
||||||
|
return globals->packageRoot()->getPackageById(ident.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
#include "QtLauncher.moc"
|
#include "QtLauncher.moc"
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,12 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QModelIndex>
|
#include <QModelIndex>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
|
||||||
#include <Airports/airport.hxx>
|
#include <Airports/airport.hxx>
|
||||||
|
#include <simgear/package/Package.hxx>
|
||||||
|
#include <simgear/package/Catalog.hxx>
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
{
|
{
|
||||||
|
@ -62,7 +66,9 @@ private slots:
|
||||||
|
|
||||||
void onAirportChoiceSelected(const QModelIndex& index);
|
void onAirportChoiceSelected(const QModelIndex& index);
|
||||||
void onAircraftSelected(const QModelIndex& index);
|
void onAircraftSelected(const QModelIndex& index);
|
||||||
|
void onRequestPackageInstall(const QModelIndex& index);
|
||||||
|
void onCancelDownload(const QModelIndex& index);
|
||||||
|
|
||||||
void onPopupAirportHistory();
|
void onPopupAirportHistory();
|
||||||
void onPopupAircraftHistory();
|
void onPopupAircraftHistory();
|
||||||
|
|
||||||
|
@ -81,6 +87,9 @@ private slots:
|
||||||
void onEditPaths();
|
void onEditPaths();
|
||||||
|
|
||||||
void onAirportDiagramClicked(FGRunwayRef rwy);
|
void onAirportDiagramClicked(FGRunwayRef rwy);
|
||||||
|
|
||||||
|
void onAircraftInstalledCompleted(QModelIndex index);
|
||||||
|
void onAircraftInstallFailed(QModelIndex index, QString errorMessage);
|
||||||
private:
|
private:
|
||||||
void setAirport(FGAirportRef ref);
|
void setAirport(FGAirportRef ref);
|
||||||
void updateSelectedAircraft();
|
void updateSelectedAircraft();
|
||||||
|
@ -88,20 +97,22 @@ private:
|
||||||
void restoreSettings();
|
void restoreSettings();
|
||||||
void saveSettings();
|
void saveSettings();
|
||||||
|
|
||||||
QModelIndex proxyIndexForAircraftPath(QString path) const;
|
QModelIndex proxyIndexForAircraftURI(QUrl uri) const;
|
||||||
QModelIndex sourceIndexForAircraftPath(QString path) const;
|
QModelIndex sourceIndexForAircraftURI(QUrl uri) const;
|
||||||
|
|
||||||
void setEnableDisableOptionFromCheckbox(QCheckBox* cbox, QString name) const;
|
void setEnableDisableOptionFromCheckbox(QCheckBox* cbox, QString name) const;
|
||||||
|
|
||||||
|
simgear::pkg::PackageRef packageForAircraftURI(QUrl uri) const;
|
||||||
|
|
||||||
QScopedPointer<Ui::Launcher> m_ui;
|
QScopedPointer<Ui::Launcher> m_ui;
|
||||||
AirportSearchModel* m_airportsModel;
|
AirportSearchModel* m_airportsModel;
|
||||||
AircraftProxyModel* m_aircraftProxy;
|
AircraftProxyModel* m_aircraftProxy;
|
||||||
AircraftItemModel* m_aircraftModel;
|
AircraftItemModel* m_aircraftModel;
|
||||||
FGAirportRef m_selectedAirport;
|
FGAirportRef m_selectedAirport;
|
||||||
|
|
||||||
QString m_selectedAircraft;
|
QUrl m_selectedAircraft;
|
||||||
QStringList m_recentAircraft,
|
QList<QUrl> m_recentAircraft;
|
||||||
m_recentAirports;
|
QStringList m_recentAirports;
|
||||||
QTimer* m_subsystemIdleTimer;
|
QTimer* m_subsystemIdleTimer;
|
||||||
|
|
||||||
int m_ratingFilters[4];
|
int m_ratingFilters[4];
|
||||||
|
|
|
@ -546,11 +546,9 @@ int fgInitAircraft(bool reinit)
|
||||||
// code in FindAndCacheAircraft works as normal
|
// code in FindAndCacheAircraft works as normal
|
||||||
// note since we may be using a variant, we can't use the package ID
|
// note since we may be using a variant, we can't use the package ID
|
||||||
size_t lastDot = aircraftId.rfind('.');
|
size_t lastDot = aircraftId.rfind('.');
|
||||||
if (lastDot != std::string::npos) {
|
assert(lastDot != std::string::npos);
|
||||||
aircraftId = aircraftId.substr(lastDot + 1);
|
aircraftId = aircraftId.substr(lastDot + 1);
|
||||||
aircraftProp->setStringValue(aircraftId);
|
aircraftProp->setStringValue(aircraftId);
|
||||||
|
|
||||||
}
|
|
||||||
// run the traditional-code path below
|
// run the traditional-code path below
|
||||||
} else {
|
} else {
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -47,9 +47,8 @@ typedef nasal::Ghost<pkg::PackageRef> NasalPackage;
|
||||||
typedef nasal::Ghost<pkg::CatalogRef> NasalCatalog;
|
typedef nasal::Ghost<pkg::CatalogRef> NasalCatalog;
|
||||||
typedef nasal::Ghost<pkg::InstallRef> NasalInstall;
|
typedef nasal::Ghost<pkg::InstallRef> NasalInstall;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
class FGHTTPClient::FGDelegate : public pkg::Delegate
|
||||||
class FGDelegate : public pkg::Delegate
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void refreshComplete()
|
virtual void refreshComplete()
|
||||||
|
@ -67,48 +66,52 @@ public:
|
||||||
r->scheduleToUpdate((*it)->install());
|
r->scheduleToUpdate((*it)->install());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void failedRefresh(pkg::Catalog* aCat, FailureCode aReason)
|
virtual void catalogRefreshed(pkg::CatalogRef aCat, StatusCode aReason)
|
||||||
{
|
{
|
||||||
|
if (aCat.ptr() == NULL) {
|
||||||
|
SG_LOG(SG_IO, SG_INFO, "refresh of all catalogs done");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (aReason) {
|
switch (aReason) {
|
||||||
case pkg::Delegate::FAIL_SUCCESS:
|
case pkg::Delegate::STATUS_SUCCESS:
|
||||||
SG_LOG(SG_IO, SG_WARN, "refresh of Catalog done");
|
case pkg::Delegate::STATUS_REFRESHED:
|
||||||
|
SG_LOG(SG_IO, SG_INFO, "refresh of Catalog done:" << aCat->url());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case pkg::Delegate::STATUS_IN_PROGRESS:
|
||||||
|
SG_LOG(SG_IO, SG_INFO, "refresh of Catalog started:" << aCat->url());
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SG_LOG(SG_IO, SG_WARN, "refresh of Catalog " << aCat->url() << " failed:" << aReason);
|
SG_LOG(SG_IO, SG_WARN, "refresh of Catalog " << aCat->url() << " failed:" << aReason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void startInstall(pkg::Install* aInstall)
|
virtual void startInstall(pkg::InstallRef aInstall)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_IO, SG_INFO, "beginning install of:" << aInstall->package()->id()
|
SG_LOG(SG_IO, SG_INFO, "beginning install of:" << aInstall->package()->id()
|
||||||
<< " to local path:" << aInstall->path());
|
<< " to local path:" << aInstall->path());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void installProgress(pkg::Install* aInstall, unsigned int aBytes, unsigned int aTotal)
|
virtual void installProgress(pkg::InstallRef aInstall, unsigned int aBytes, unsigned int aTotal)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_IO, SG_INFO, "installing:" << aInstall->package()->id() << ":"
|
|
||||||
<< aBytes << " of " << aTotal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void finishInstall(pkg::Install* aInstall)
|
virtual void finishInstall(pkg::InstallRef aInstall, StatusCode aReason)
|
||||||
{
|
{
|
||||||
|
if (aReason == STATUS_SUCCESS) {
|
||||||
SG_LOG(SG_IO, SG_INFO, "finished install of:" << aInstall->package()->id()
|
SG_LOG(SG_IO, SG_INFO, "finished install of:" << aInstall->package()->id()
|
||||||
<< " to local path:" << aInstall->path());
|
<< " to local path:" << aInstall->path());
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "install failed of:" << aInstall->package()->id()
|
||||||
|
<< " to local path:" << aInstall->path());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}; // of FGHTTPClient::FGDelegate
|
||||||
virtual void failedInstall(pkg::Install* aInstall, FailureCode aReason)
|
|
||||||
{
|
|
||||||
SG_LOG(SG_IO, SG_WARN, "install failed of:" << aInstall->package()->id()
|
|
||||||
<< " to local path:" << aInstall->path());
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // of anonymous namespace
|
|
||||||
|
|
||||||
FGHTTPClient::FGHTTPClient() :
|
FGHTTPClient::FGHTTPClient() :
|
||||||
_inited(false)
|
_inited(false)
|
||||||
|
@ -142,11 +145,12 @@ void FGHTTPClient::init()
|
||||||
// package system needs access to the HTTP engine too
|
// package system needs access to the HTTP engine too
|
||||||
packageRoot->setHTTPClient(_http.get());
|
packageRoot->setHTTPClient(_http.get());
|
||||||
|
|
||||||
packageRoot->setDelegate(new FGDelegate);
|
_packageDelegate.reset(new FGDelegate);
|
||||||
|
packageRoot->addDelegate(_packageDelegate.get());
|
||||||
|
|
||||||
const char * defaultCatalogId = fgGetString("/sim/package-system/default-catalog/id", "org.flightgear.default" );
|
const char * defaultCatalogId = fgGetString("/sim/package-system/default-catalog/id", "org.flightgear.official" );
|
||||||
const char * defaultCatalogUrl = fgGetString("/sim/package-system/default-catalog/url",
|
const char * defaultCatalogUrl = fgGetString("/sim/package-system/default-catalog/url",
|
||||||
"http://fgfs.goneabitbursar.com/pkg/" FLIGHTGEAR_VERSION "/default-catalog.xml");
|
"http://fgfs.goneabitbursar.com/pkg/" FLIGHTGEAR_VERSION "/catalog.xml");
|
||||||
// setup default catalog if not present
|
// setup default catalog if not present
|
||||||
pkg::Catalog* defaultCatalog = packageRoot->getCatalogById( defaultCatalogId );
|
pkg::Catalog* defaultCatalog = packageRoot->getCatalogById( defaultCatalogId );
|
||||||
if (!defaultCatalog) {
|
if (!defaultCatalog) {
|
||||||
|
@ -299,7 +303,13 @@ void FGHTTPClient::postinit()
|
||||||
|
|
||||||
void FGHTTPClient::shutdown()
|
void FGHTTPClient::shutdown()
|
||||||
{
|
{
|
||||||
_http.reset();
|
pkg::Root* packageRoot = globals->packageRoot();
|
||||||
|
if (packageRoot && _packageDelegate.get()) {
|
||||||
|
packageRoot->removeDelegate(_packageDelegate.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
_packageDelegate.reset();
|
||||||
|
_http.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGHTTPClient::update(double)
|
void FGHTTPClient::update(double)
|
||||||
|
|
|
@ -42,8 +42,11 @@ public:
|
||||||
virtual void update(double);
|
virtual void update(double);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class FGDelegate;
|
||||||
|
|
||||||
bool _inited;
|
bool _inited;
|
||||||
std::auto_ptr<simgear::HTTP::Client> _http;
|
std::auto_ptr<simgear::HTTP::Client> _http;
|
||||||
|
std::auto_ptr<FGDelegate> _packageDelegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FG_HTTP_CLIENT_HXX
|
#endif // FG_HTTP_CLIENT_HXX
|
||||||
|
|
Loading…
Add table
Reference in a new issue