1
0
Fork 0

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:
James Turner 2015-03-05 17:39:37 +00:00
parent 4038ba3d51
commit 8d9db2824e

View file

@ -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());