1
0
Fork 0

Prompt the user when the default hangar is missing.

In the Qt launcher, when the default hangar isn’t found, show
a hint in the aircraft list.
This commit is contained in:
James Turner 2016-04-15 17:06:53 +01:00
parent c15e4753ac
commit 6095646a62
9 changed files with 256 additions and 36 deletions

View file

@ -43,7 +43,21 @@ AircraftItemDelegate::AircraftItemDelegate(QListView* view) :
void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option,
const QModelIndex & index) const
{
painter->setRenderHint(QPainter::Antialiasing);
QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
QVariant v = index.data(AircraftPackageStatusRole);
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
if (status == NoOfficialCatalogMessage) {
painter->setPen(QColor(0x7f, 0x7f, 0x7f));
painter->setBrush(Qt::NoBrush);
// draw bottom dividing line
painter->drawLine(contentRect.left(), contentRect.bottom() + MARGIN,
contentRect.right(), contentRect.bottom() + MARGIN);
return;
}
// selection feedback rendering
if (option.state & QStyle::State_Selected) {
QLinearGradient grad(option.rect.topLeft(), option.rect.bottomLeft());
@ -57,7 +71,6 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
painter->drawLine(option.rect.topLeft(), option.rect.topRight());
}
QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
QPixmap thumbnail = index.data(Qt::DecorationRole).value<QPixmap>();
quint32 yPos = contentRect.center().y() - (thumbnail.height() / 2);
@ -130,6 +143,8 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
r.moveLeft(r.right());
r.setHeight(qMax(24, smallMetrics.height() + MARGIN));
painter->setRenderHint(QPainter::Antialiasing, true);
if (index.data(AircraftHasRatingsRole).toBool()) {
drawRating(painter, "Flight model:", r, index.data(AircraftRatingRole).toInt());
r.moveTop(r.bottom());
@ -142,8 +157,6 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
drawRating(painter, "Exterior:", r, index.data(AircraftRatingRole + 3).toInt());
}
QVariant v = index.data(AircraftPackageStatusRole);
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
double downloadFraction = 0.0;
if (status != PackageInstalled) {
@ -205,10 +218,22 @@ void AircraftItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem
painter->setPen(Qt::black);
painter->drawText(infoTextRect, Qt::AlignLeft | Qt::AlignVCenter, infoText);
} // of update / install / download status
painter->setRenderHint(QPainter::Antialiasing, false);
}
QSize AircraftItemDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
QVariant v = index.data(AircraftPackageStatusRole);
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
if (status == NoOfficialCatalogMessage) {
QSize r = option.rect.size();
r.setHeight(100);
return r;
}
QRect contentRect = option.rect.adjusted(MARGIN, MARGIN, -MARGIN, -MARGIN);
QSize thumbnailSize = index.data(AircraftThumbnailSizeRole).toSize();

View file

@ -434,7 +434,8 @@ private:
AircraftItemModel::AircraftItemModel(QObject* pr ) :
QAbstractListModel(pr),
m_scanThread(NULL)
m_scanThread(NULL),
m_showOfficialHangarMessage(false)
{
}
@ -465,14 +466,48 @@ void AircraftItemModel::setPaths(QStringList paths)
m_paths = paths;
}
void AircraftItemModel::setOfficialHangarMessageVisible(bool vis)
{
if (m_showOfficialHangarMessage == vis) {
return;
}
m_showOfficialHangarMessage = vis;
if (vis) {
beginInsertRows(QModelIndex(), 0, 0);
m_items.prepend(AircraftItemPtr(new AircraftItem));
m_activeVariant.prepend(0);
endInsertRows();
} else {
beginRemoveRows(QModelIndex(), 0, 0);
m_items.removeAt(0);
m_activeVariant.removeAt(0);
endRemoveRows();
}
}
QModelIndex AircraftItemModel::officialHangarMessageIndex() const
{
if (!m_showOfficialHangarMessage) {
return QModelIndex();
}
return index(0);
}
void AircraftItemModel::scanDirs()
{
abandonCurrentScan();
beginResetModel();
m_items.clear();
m_activeVariant.clear();
endResetModel();
int firstRow = (m_showOfficialHangarMessage ? 1 : 0);
int numToRemove = m_items.size() - firstRow;
int lastRow = firstRow + numToRemove - 1;
beginRemoveRows(QModelIndex(), firstRow, lastRow);
m_items.remove(firstRow, numToRemove);
m_activeVariant.remove(firstRow, numToRemove);
endRemoveRows();
QStringList dirs = m_paths;
@ -504,10 +539,34 @@ void AircraftItemModel::abandonCurrentScan()
void AircraftItemModel::refreshPackages()
{
beginResetModel();
m_packages = m_packageRoot->allPackages();
m_packageVariant.resize(m_packages.size());
endResetModel();
simgear::pkg::PackageList newPkgs = m_packageRoot->allPackages();
int firstRow = m_items.size();
int newSize = newPkgs.size();
if (m_packages.size() != newPkgs.size()) {
int oldSize = m_packages.size();
if (newSize > oldSize) {
// growing
int firstNewRow = firstRow + oldSize;
int lastNewRow = firstRow + newSize - 1;
beginInsertRows(QModelIndex(), firstNewRow, lastNewRow);
m_packages = newPkgs;
m_packageVariant.resize(newSize);
endInsertRows();
} else {
// shrinking
int firstOldRow = firstRow + newSize;
int lastOldRow = firstRow + oldSize - 1;
beginRemoveRows(QModelIndex(), firstOldRow, lastOldRow);
m_packages = newPkgs;
m_packageVariant.resize(newSize);
endRemoveRows();
}
} else {
m_packages = newPkgs;
}
emit dataChanged(index(firstRow), index(firstRow + newSize - 1));
}
int AircraftItemModel::rowCount(const QModelIndex& parent) const
@ -517,8 +576,19 @@ int AircraftItemModel::rowCount(const QModelIndex& parent) const
QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
{
if (index.row() >= m_items.size()) {
quint32 packageIndex = index.row() - m_items.size();
int row = index.row();
if (m_showOfficialHangarMessage) {
if (row == 0) {
if (role == AircraftPackageStatusRole) {
return NoOfficialCatalogMessage;
}
return QVariant();
}
}
if (row >= m_items.size()) {
quint32 packageIndex = row - m_items.size();
if (role == AircraftVariantRole) {
return m_packageVariant.at(packageIndex);
@ -537,11 +607,11 @@ QVariant AircraftItemModel::data(const QModelIndex& index, int role) const
return dataFromPackage(pkg, variantIndex, role);
} else {
if (role == AircraftVariantRole) {
return m_activeVariant.at(index.row());
return m_activeVariant.at(row);
}
quint32 variantIndex = m_activeVariant.at(index.row());
const AircraftItemPtr item(m_items.at(index.row()));
quint32 variantIndex = m_activeVariant.at(row);
const AircraftItemPtr item(m_items.at(row));
return dataFromItem(item, variantIndex, role);
}
}
@ -761,6 +831,10 @@ bool AircraftItemModel::setData(const QModelIndex &index, const QVariant &value,
QModelIndex AircraftItemModel::indexOfAircraftURI(QUrl uri) const
{
if (uri.isEmpty()) {
return QModelIndex();
}
if (uri.isLocalFile()) {
QString path = uri.toLocalFile();
for (int row=0; row <m_items.size(); ++row) {
@ -778,11 +852,13 @@ QModelIndex AircraftItemModel::indexOfAircraftURI(QUrl uri) const
}
} else if (uri.scheme() == "package") {
QString ident = uri.path();
int rowOffset = m_items.size();
PackageRef pkg = m_packageRoot->getPackageById(ident.toStdString());
if (pkg) {
for (size_t i=0; i < m_packages.size(); ++i) {
if (m_packages[i] == pkg) {
return index(m_items.size() + i);
return index(rowOffset + i);
}
} // of linear package scan
}
@ -820,8 +896,6 @@ void AircraftItemModel::onScanFinished()
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:

View file

@ -94,7 +94,8 @@ enum AircraftItemStatus {
PackageInstalled,
PackageUpdateAvailable,
PackageQueued,
PackageDownloading
PackageDownloading,
NoOfficialCatalogMessage
};
class AircraftItemModel : public QAbstractListModel
@ -130,6 +131,14 @@ public:
*/
bool isIndexRunnable(const QModelIndex& index) const;
/**
* should we show the prompt about the official hangar not being installed
* or not?
*/
void setOfficialHangarMessageVisible(bool vis);
QModelIndex officialHangarMessageIndex() const;
/**
* @helper to determine if a particular path is likely to contain
* aircraft or not. Checks for -set.xml files one level down in the tree.
@ -157,7 +166,7 @@ private:
quint32 variantIndex, int role) const;
QVariant packageThumbnail(simgear::pkg::PackageRef p, int index, bool download = true) const;
void abandonCurrentScan();
void refreshPackages();
@ -168,7 +177,8 @@ private:
AircraftScanThread* m_scanThread;
QVector<AircraftItemPtr> m_items;
PackageDelegate* m_delegate;
bool m_showOfficialHangarMessage;
QVector<quint32> m_activeVariant;
QVector<quint32> m_packageVariant;

View file

@ -75,7 +75,8 @@ if (HAVE_QT)
SetupRootDialog.ui
AddCatalogDialog.ui
PathsDialog.ui
LocationWidget.ui)
LocationWidget.ui
NoOfficialHanagar.ui)
qt5_add_resources(qrc_sources resources.qrc)

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NoOfficialHangarMessage</class>
<widget class="QWidget" name="NoOfficialHangarMessage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>134</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The official FlightGear aircraft hangar is not selected, so only the default aircraft will be available. You can add the official hangar by &lt;a href=&quot;action:add-official&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;clicking here&lt;/span&gt;&lt;/a&gt;, or go to the 'add-ons' page to add other hangars or aircraft folders.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;action:hide&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Click here&lt;/span&gt;&lt;/a&gt; to permanently hide this message.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -190,20 +190,25 @@ void AddOnsPage::onAddCatalog()
}
void AddOnsPage::onAddDefaultCatalog()
{
addDefaultCatalog(this);
m_catalogsModel->refresh();
updateUi();
}
void AddOnsPage::addDefaultCatalog(QWidget* pr)
{
// check it's not a duplicate somehow
FGHTTPClient* http = globals->get_subsystem<FGHTTPClient>();
if (http->isDefaultCatalogInstalled())
return;
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(this, m_packageRoot));
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
dlg->setUrlAndDownload(url);
dlg->exec();
if (dlg->result() == QDialog::Accepted) {
m_catalogsModel->refresh();
updateUi();
}
QScopedPointer<AddCatalogDialog> dlg(new AddCatalogDialog(pr, globals->packageRoot()));
QUrl url(QString::fromStdString(http->getDefaultCatalogUrl()));
dlg->setUrlAndDownload(url);
dlg->exec();
}
void AddOnsPage::onRemoveCatalog()

View file

@ -20,6 +20,8 @@ public:
explicit AddOnsPage(QWidget *parent, simgear::pkg::RootRef root);
~AddOnsPage();
static void addDefaultCatalog(QWidget* pr);
signals:
void downloadDirChanged();
void sceneryPathsChanged();

View file

@ -59,6 +59,8 @@
#include <simgear/package/Install.hxx>
#include "ui_Launcher.h"
#include "ui_NoOfficialHangar.h"
#include "EditRatingsFilterDialog.hxx"
#include "AircraftItemDelegate.hxx"
#include "AircraftModel.hxx"
@ -293,12 +295,18 @@ public slots:
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
QVariant v = index.data(AircraftPackageStatusRole);
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
if (status == NoOfficialCatalogMessage) {
return true;
}
if (!QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent)) {
return false;
}
if (m_onlyShowInstalled) {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
QVariant v = index.data(AircraftPackageStatusRole);
AircraftItemStatus status = static_cast<AircraftItemStatus>(v.toInt());
if (status == PackageNotInstalled) {
@ -307,7 +315,6 @@ protected:
}
if (!m_onlyShowInstalled && m_ratingsFilter) {
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
for (int i=0; i<4; ++i) {
if (m_ratings[i] > index.data(AircraftRatingRole + i).toInt()) {
return false;
@ -324,6 +331,26 @@ private:
int m_ratings[4];
};
class NoOfficialHangarMessage : public QWidget
{
Q_OBJECT
public:
NoOfficialHangarMessage() :
m_ui(new Ui::NoOfficialHangarMessage)
{
m_ui->setupUi(this);
// proxy this signal upwards
connect(m_ui->label, &QLabel::linkActivated,
this, &NoOfficialHangarMessage::linkActivated);
}
Q_SIGNALS:
void linkActivated(QUrl link);
private:
Ui::NoOfficialHangarMessage* m_ui;
};
static void initQtResources()
{
Q_INIT_RESOURCE(resources);
@ -593,6 +620,7 @@ QtLauncher::QtLauncher() :
m_aircraftModel->setPackageRoot(globals->packageRoot());
m_aircraftModel->scanDirs();
checkOfficialCatalogMessage();
restoreSettings();
}
@ -1163,6 +1191,7 @@ void QtLauncher::onSubsytemIdleTimeout()
void QtLauncher::onDownloadDirChanged()
{
// replace existing package root
globals->get_subsystem<FGHTTPClient>()->shutdown();
globals->setPackageRoot(simgear::pkg::RootRef());
@ -1172,16 +1201,50 @@ void QtLauncher::onDownloadDirChanged()
globals->get_subsystem<FGHTTPClient>()->init();
// re-scan the aircraft list
QSettings settings;
// re-scan the aircraft list
m_aircraftModel->setPackageRoot(globals->packageRoot());
m_aircraftModel->setPaths(settings.value("aircraft-paths").toStringList());
m_aircraftModel->scanDirs();
checkOfficialCatalogMessage();
// re-set scenery dirs
setSceneryPaths();
}
void QtLauncher::checkOfficialCatalogMessage()
{
QSettings settings;
bool showOfficialCatalogMesssage = !globals->get_subsystem<FGHTTPClient>()->isDefaultCatalogInstalled();
if (settings.value("hide-official-catalog-message").toBool()) {
showOfficialCatalogMesssage = false;
}
m_aircraftModel->setOfficialHangarMessageVisible(showOfficialCatalogMesssage);
if (showOfficialCatalogMesssage) {
NoOfficialHangarMessage* messageWidget = new NoOfficialHangarMessage;
connect(messageWidget, &NoOfficialHangarMessage::linkActivated,
this, &QtLauncher::onOfficialCatalogMessageLink);
QModelIndex index = m_aircraftProxy->mapFromSource(m_aircraftModel->officialHangarMessageIndex());
m_ui->aircraftList->setIndexWidget(index, messageWidget);
}
}
void QtLauncher::onOfficialCatalogMessageLink(QUrl link)
{
QString s = link.toString();
if (s == "action:hide") {
QSettings settings;
settings.setValue("hide-official-catalog-message", true);
} else if (s == "action:add-official") {
AddOnsPage::addDefaultCatalog(this);
}
checkOfficialCatalogMessage();
}
simgear::pkg::PackageRef QtLauncher::packageForAircraftURI(QUrl uri) const
{
if (uri.scheme() != "package") {

View file

@ -115,6 +115,9 @@ private:
simgear::pkg::PackageRef packageForAircraftURI(QUrl uri) const;
void checkOfficialCatalogMessage();
void onOfficialCatalogMessageLink(QUrl link);
// need to wait after a model reset before restoring selection and
// scrolling, to give the view time it seems.
void delayedAircraftModelReset();