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 <QFileDialog>
#include <QMessageBox>
#include <QDataStream>
#include <QDateTime>
// Simgear
#include <simgear/timing/timestamp.hxx>
@ -96,6 +98,8 @@ struct AircraftItem
SGPropertyNode_ptr sim = root.getNode("sim");
path = filePath;
pathModTime = QFileInfo(path).lastModified();
description = sim->getStringValue("description");
authors = sim->getStringValue("author");
@ -106,15 +110,6 @@ struct AircraftItem
if (sim->hasChild("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
@ -125,15 +120,49 @@ struct AircraftItem
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;
QPixmap thumbnail;
QString description;
QString authors;
int ratings[4];
QString variantOf;
QDateTime pathModTime;
QList<AircraftItem*> variants;
private:
mutable QPixmap m_thumbnail;
void parseRatings(SGPropertyNode_ptr ratingsNode)
{
ratings[0] = ratingsNode->getIntValue("FDM");
@ -143,6 +172,8 @@ private:
}
};
static int CACHE_VERSION = 2;
class AircraftScanThread : public QThread
{
Q_OBJECT
@ -151,7 +182,10 @@ public:
m_dirs(dirsToScan),
m_done(false)
{
}
~AircraftScanThread()
{
}
/** thread-safe access to items already scanned */
@ -174,17 +208,70 @@ Q_SIGNALS:
protected:
virtual void run()
{
readCache();
Q_FOREACH(QString d, m_dirs) {
scanAircraftDir(QDir(d));
if (m_done) {
return;
}
}
writeCache();
}
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)
{
QTime t;
t.start();
QStringList filters;
filters << "*-set.xml";
Q_FOREACH(QFileInfo child, path.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) {
@ -194,7 +281,17 @@ private:
Q_FOREACH(QFileInfo xmlChild, childDir.entryInfoList(filters, QDir::Files)) {
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()) {
baseAircraft.insert(item->baseName(), item);
} else {
@ -220,7 +317,7 @@ private:
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);
m_items.append(baseAircraft.values());
@ -228,11 +325,17 @@ private:
emit addedItems();
} // of subdir iteration
qDebug() << "scan of" << path << "took" << t.elapsed();
}
QMutex m_lock;
QStringList m_dirs;
QList<AircraftItem*> m_items;
QMap<QString, AircraftItem* > m_cachedItems;
QMap<QString, AircraftItem* > m_nextCache;
bool m_done;
};
@ -302,7 +405,7 @@ public:
if (role == Qt::DisplayRole) {
return item->description;
} else if (role == Qt::DecorationRole) {
return item->thumbnail;
return item->thumbnail();
} else if (role == AircraftPathRole) {
return item->path;
} else if (role == AircraftAuthorsRole) {
@ -1282,7 +1385,7 @@ void QtLauncher::updateSelectedAircraft()
try {
QFileInfo info(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);
} catch (sg_exception& e) {
m_ui->thumbnail->setPixmap(QPixmap());