Launch aircraft data cache
- makes successive aircraft scans much faster since -set.xml parsing can be skipped when the file is unmodified.
This commit is contained in:
parent
4038ba3d51
commit
8d9db2824e
1 changed files with 117 additions and 14 deletions
|
@ -25,6 +25,8 @@
|
||||||
#include <QLinearGradient>
|
#include <QLinearGradient>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
// Simgear
|
// Simgear
|
||||||
#include <simgear/timing/timestamp.hxx>
|
#include <simgear/timing/timestamp.hxx>
|
||||||
|
@ -96,6 +98,8 @@ struct AircraftItem
|
||||||
SGPropertyNode_ptr sim = root.getNode("sim");
|
SGPropertyNode_ptr sim = root.getNode("sim");
|
||||||
|
|
||||||
path = filePath;
|
path = filePath;
|
||||||
|
pathModTime = QFileInfo(path).lastModified();
|
||||||
|
|
||||||
description = sim->getStringValue("description");
|
description = sim->getStringValue("description");
|
||||||
authors = sim->getStringValue("author");
|
authors = sim->getStringValue("author");
|
||||||
|
|
||||||
|
@ -106,15 +110,6 @@ struct AircraftItem
|
||||||
if (sim->hasChild("variant-of")) {
|
if (sim->hasChild("variant-of")) {
|
||||||
variantOf = sim->getStringValue("variant-of");
|
variantOf = sim->getStringValue("variant-of");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir.exists("thumbnail.jpg")) {
|
|
||||||
thumbnail.load(dir.filePath("thumbnail.jpg"));
|
|
||||||
// resize to the standard size
|
|
||||||
if (thumbnail.height() > 128) {
|
|
||||||
thumbnail = thumbnail.scaledToHeight(128);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the file-name without -set.xml suffix
|
// the file-name without -set.xml suffix
|
||||||
|
@ -125,15 +120,49 @@ struct AircraftItem
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fromDataStream(QDataStream& ds)
|
||||||
|
{
|
||||||
|
ds >> path >> description >> authors >> variantOf;
|
||||||
|
for (int i=0; i<4; ++i) ds >> ratings[i];
|
||||||
|
ds >> pathModTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toDataStream(QDataStream& ds) const
|
||||||
|
{
|
||||||
|
ds << path << description << authors << variantOf;
|
||||||
|
for (int i=0; i<4; ++i) ds << ratings[i];
|
||||||
|
ds << pathModTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPixmap thumbnail() const
|
||||||
|
{
|
||||||
|
if (m_thumbnail.isNull()) {
|
||||||
|
QFileInfo info(path);
|
||||||
|
QDir dir = info.dir();
|
||||||
|
if (dir.exists("thumbnail.jpg")) {
|
||||||
|
m_thumbnail.load(dir.filePath("thumbnail.jpg"));
|
||||||
|
// resize to the standard size
|
||||||
|
if (m_thumbnail.height() > 128) {
|
||||||
|
m_thumbnail = m_thumbnail.scaledToHeight(128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
QString path;
|
QString path;
|
||||||
QPixmap thumbnail;
|
|
||||||
QString description;
|
QString description;
|
||||||
QString authors;
|
QString authors;
|
||||||
int ratings[4];
|
int ratings[4];
|
||||||
QString variantOf;
|
QString variantOf;
|
||||||
|
QDateTime pathModTime;
|
||||||
|
|
||||||
QList<AircraftItem*> variants;
|
QList<AircraftItem*> variants;
|
||||||
private:
|
private:
|
||||||
|
mutable QPixmap m_thumbnail;
|
||||||
|
|
||||||
|
|
||||||
void parseRatings(SGPropertyNode_ptr ratingsNode)
|
void parseRatings(SGPropertyNode_ptr ratingsNode)
|
||||||
{
|
{
|
||||||
ratings[0] = ratingsNode->getIntValue("FDM");
|
ratings[0] = ratingsNode->getIntValue("FDM");
|
||||||
|
@ -143,6 +172,8 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int CACHE_VERSION = 2;
|
||||||
|
|
||||||
class AircraftScanThread : public QThread
|
class AircraftScanThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -151,7 +182,10 @@ public:
|
||||||
m_dirs(dirsToScan),
|
m_dirs(dirsToScan),
|
||||||
m_done(false)
|
m_done(false)
|
||||||
{
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~AircraftScanThread()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** thread-safe access to items already scanned */
|
/** thread-safe access to items already scanned */
|
||||||
|
@ -174,17 +208,70 @@ Q_SIGNALS:
|
||||||
protected:
|
protected:
|
||||||
virtual void run()
|
virtual void run()
|
||||||
{
|
{
|
||||||
|
readCache();
|
||||||
|
|
||||||
Q_FOREACH(QString d, m_dirs) {
|
Q_FOREACH(QString d, m_dirs) {
|
||||||
scanAircraftDir(QDir(d));
|
scanAircraftDir(QDir(d));
|
||||||
if (m_done) {
|
if (m_done) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void readCache()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
QByteArray cacheData = settings.value("aircraft-cache").toByteArray();
|
||||||
|
if (!cacheData.isEmpty()) {
|
||||||
|
QDataStream ds(cacheData);
|
||||||
|
quint32 count, cacheVersion;
|
||||||
|
ds >> cacheVersion >> count;
|
||||||
|
|
||||||
|
if (cacheVersion != CACHE_VERSION) {
|
||||||
|
return; // mis-matched cache, version, drop
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<count; ++i) {
|
||||||
|
AircraftItem* item = new AircraftItem;
|
||||||
|
item->fromDataStream(ds);
|
||||||
|
|
||||||
|
QFileInfo finfo(item->path);
|
||||||
|
if (!finfo.exists() || (finfo.lastModified() != item->pathModTime)) {
|
||||||
|
delete item;
|
||||||
|
} else {
|
||||||
|
// corresponding -set.xml file still exists and is
|
||||||
|
// unmodified
|
||||||
|
m_cachedItems[item->path] = item;
|
||||||
|
}
|
||||||
|
} // of cached item iteration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeCache()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
QByteArray cacheData;
|
||||||
|
{
|
||||||
|
QDataStream ds(&cacheData, QIODevice::WriteOnly);
|
||||||
|
quint32 count = m_nextCache.count();
|
||||||
|
ds << CACHE_VERSION << count;
|
||||||
|
|
||||||
|
Q_FOREACH(AircraftItem* item, m_nextCache.values()) {
|
||||||
|
item->toDataStream(ds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.setValue("aircraft-cache", cacheData);
|
||||||
|
}
|
||||||
|
|
||||||
void scanAircraftDir(QDir path)
|
void scanAircraftDir(QDir path)
|
||||||
{
|
{
|
||||||
|
QTime t;
|
||||||
|
t.start();
|
||||||
|
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
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)) {
|
||||||
|
@ -194,7 +281,17 @@ private:
|
||||||
|
|
||||||
Q_FOREACH(QFileInfo xmlChild, childDir.entryInfoList(filters, QDir::Files)) {
|
Q_FOREACH(QFileInfo xmlChild, childDir.entryInfoList(filters, QDir::Files)) {
|
||||||
try {
|
try {
|
||||||
AircraftItem* item = new AircraftItem(childDir, xmlChild.absoluteFilePath());
|
QString absolutePath = xmlChild.absoluteFilePath();
|
||||||
|
AircraftItem* item = NULL;
|
||||||
|
|
||||||
|
if (m_cachedItems.contains(absolutePath)) {
|
||||||
|
item = m_cachedItems.value(absolutePath);
|
||||||
|
} else {
|
||||||
|
item = new AircraftItem(childDir, absolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_nextCache[absolutePath] = item;
|
||||||
|
|
||||||
if (item->variantOf.isNull()) {
|
if (item->variantOf.isNull()) {
|
||||||
baseAircraft.insert(item->baseName(), item);
|
baseAircraft.insert(item->baseName(), item);
|
||||||
} else {
|
} else {
|
||||||
|
@ -220,7 +317,7 @@ private:
|
||||||
baseAircraft.value(item->variantOf)->variants.append(item);
|
baseAircraft.value(item->variantOf)->variants.append(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// lock mutex whil 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());
|
||||||
|
@ -228,11 +325,17 @@ private:
|
||||||
|
|
||||||
emit addedItems();
|
emit addedItems();
|
||||||
} // of subdir iteration
|
} // of subdir iteration
|
||||||
|
|
||||||
|
qDebug() << "scan of" << path << "took" << t.elapsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutex m_lock;
|
QMutex m_lock;
|
||||||
QStringList m_dirs;
|
QStringList m_dirs;
|
||||||
QList<AircraftItem*> m_items;
|
QList<AircraftItem*> m_items;
|
||||||
|
|
||||||
|
QMap<QString, AircraftItem* > m_cachedItems;
|
||||||
|
QMap<QString, AircraftItem* > m_nextCache;
|
||||||
|
|
||||||
bool m_done;
|
bool m_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -302,7 +405,7 @@ public:
|
||||||
if (role == Qt::DisplayRole) {
|
if (role == Qt::DisplayRole) {
|
||||||
return item->description;
|
return item->description;
|
||||||
} else if (role == Qt::DecorationRole) {
|
} else if (role == Qt::DecorationRole) {
|
||||||
return item->thumbnail;
|
return item->thumbnail();
|
||||||
} else if (role == AircraftPathRole) {
|
} else if (role == AircraftPathRole) {
|
||||||
return item->path;
|
return item->path;
|
||||||
} else if (role == AircraftAuthorsRole) {
|
} else if (role == AircraftAuthorsRole) {
|
||||||
|
@ -1282,7 +1385,7 @@ void QtLauncher::updateSelectedAircraft()
|
||||||
try {
|
try {
|
||||||
QFileInfo info(m_selectedAircraft);
|
QFileInfo info(m_selectedAircraft);
|
||||||
AircraftItem item(info.dir(), m_selectedAircraft);
|
AircraftItem item(info.dir(), m_selectedAircraft);
|
||||||
m_ui->thumbnail->setPixmap(item.thumbnail);
|
m_ui->thumbnail->setPixmap(item.thumbnail());
|
||||||
m_ui->aircraftDescription->setText(item.description);
|
m_ui->aircraftDescription->setText(item.description);
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
m_ui->thumbnail->setPixmap(QPixmap());
|
m_ui->thumbnail->setPixmap(QPixmap());
|
||||||
|
|
Loading…
Reference in a new issue