Threaded picture caching

This commit is contained in:
brukie 2011-01-19 00:16:41 +01:00
parent 9ece3cb789
commit dc0f21cce4
9 changed files with 139 additions and 78 deletions

View file

@ -28,7 +28,6 @@ HEADERS += src/abstractcounter.h \
src/handcounter.h \
src/carddatabase.h \
src/gameview.h \
src/deck_picturecacher.h \
src/decklistmodel.h \
src/dlg_load_deck_from_clipboard.h \
src/dlg_load_remote_deck.h \
@ -111,7 +110,6 @@ SOURCES += src/abstractcounter.cpp \
src/handcounter.cpp \
src/carddatabase.cpp \
src/gameview.cpp \
src/deck_picturecacher.cpp \
src/decklistmodel.cpp \
src/dlg_load_deck_from_clipboard.cpp \
src/dlg_load_remote_deck.cpp \

View file

@ -60,6 +60,62 @@ void SetList::sortByKey()
qSort(begin(), end(), CompareFunctor());
}
PictureLoadingThread::PictureLoadingThread(QObject *parent)
: QThread(parent)
{
}
PictureLoadingThread::~PictureLoadingThread()
{
quit();
wait();
}
void PictureLoadingThread::run()
{
forever {
mutex.lock();
if (loadQueue.isEmpty()) {
mutex.unlock();
return;
}
CardInfo *card = loadQueue.takeFirst();
QString correctedName = card->getCorrectedName();
QString picsPath = _picsPath;
SetList sortedSets = card->getSets();
mutex.unlock();
sortedSets.sortByKey();
QImage image;
for (int i = 0; i < sortedSets.size(); i++) {
if (image.load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg(sortedSets[i]->getShortName()).arg(correctedName)))
break;
if (image.load(QString("%1/%2/%3%4.full.jpg").arg(picsPath).arg(sortedSets[i]->getShortName()).arg(correctedName).arg(1)))
break;
}
if (image.isNull())
image.load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg("downloadedPics").arg(correctedName));
emit imageLoaded(card, image);
}
}
void PictureLoadingThread::loadImage(CardInfo *card)
{
QMutexLocker locker(&mutex);
loadQueue.append(card);
if (!isRunning())
start(LowPriority);
}
void PictureLoadingThread::setPicsPath(const QString &path)
{
QMutexLocker locker(&mutex);
_picsPath = path;
}
CardInfo::CardInfo(CardDatabase *_db, const QString &_name, const QString &_manacost, const QString &_cardtype, const QString &_powtough, const QString &_text, const QStringList &_colors, bool _cipt, int _tableRow, const SetList &_sets, const QString &_picURL)
: db(_db), name(_name), sets(_sets), manacost(_manacost), cardtype(_cardtype), powtough(_powtough), text(_text), colors(_colors), picURL(_picURL), cipt(_cipt), tableRow(_tableRow), pixmap(NULL)
{
@ -119,34 +175,22 @@ QPixmap *CardInfo::loadPixmap()
if (pixmap)
return pixmap;
pixmap = new QPixmap();
QString picsPath = settingsCache->getPicsPath();
if (!QDir(picsPath).exists())
return pixmap;
if (getName().isEmpty()) {
pixmap->load(settingsCache->getCardBackPicturePath());
return pixmap;
}
SetList sortedSets = sets;
sortedSets.sortByKey();
db->loadImage(this);
return pixmap;
}
QString debugOutput = QString("CardDatabase: loading pixmap for '%1' from ").arg(getName());
for (int i = 0; i < sortedSets.size(); i++)
debugOutput.append(QString("%1, ").arg(sortedSets[i]->getShortName()));
qDebug(debugOutput.toLatin1());
QString correctedName = getCorrectedName();
for (int i = 0; i < sortedSets.size(); i++) {
if (pixmap->load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg(sortedSets[i]->getShortName()).arg(correctedName)))
return pixmap;
if (pixmap->load(QString("%1/%2/%3%4.full.jpg").arg(picsPath).arg(sortedSets[i]->getShortName()).arg(correctedName).arg(1)))
return pixmap;
}
if (pixmap->load(QString("%1/%2/%3.full.jpg").arg(picsPath).arg("downloadedPics").arg(correctedName)))
return pixmap;
if (settingsCache->getPicDownload())
void CardInfo::imageLoaded(const QImage &image)
{
if (!image.isNull()) {
*pixmap = QPixmap::fromImage(image);
emit pixmapUpdated();
} else if (settingsCache->getPicDownload())
db->startPicDownload(this);
return pixmap;
}
QPixmap *CardInfo::getPixmap(QSize size)
@ -244,6 +288,11 @@ CardDatabase::CardDatabase(QObject *parent)
loadCardDatabase();
loadingThread = new PictureLoadingThread(this);
loadingThread->setPicsPath(settingsCache->getPicsPath());
connect(loadingThread, SIGNAL(imageLoaded(CardInfo *, QImage)), this, SLOT(imageLoaded(CardInfo *, QImage)));
loadingThread->start();
noCard = new CardInfo(this);
noCard->loadPixmap(); // cache pixmap for card back
connect(settingsCache, SIGNAL(cardBackPicturePathChanged()), noCard, SLOT(updatePixmapCache()));
@ -532,3 +581,21 @@ QStringList CardDatabase::getAllMainCardTypes() const
types.insert(cardIterator.next().value()->getMainCardType());
return types.toList();
}
void CardDatabase::cacheCardPixmaps(const QStringList &cardNames)
{
qDebug("pixmapCache started");
for (int i = 0; i < cardNames.size(); ++i)
getCard(cardNames[i])->loadPixmap();
qDebug("pixmapCache finished");
}
void CardDatabase::loadImage(CardInfo *card)
{
loadingThread->loadImage(card);
}
void CardDatabase::imageLoaded(CardInfo *card, QImage image)
{
card->imageLoaded(image);
}

View file

@ -8,6 +8,8 @@
#include <QList>
#include <QXmlStreamReader>
#include <QNetworkRequest>
#include <QThread>
#include <QMutex>
class CardDatabase;
class CardInfo;
@ -35,6 +37,23 @@ public:
void sortByKey();
};
class PictureLoadingThread : public QThread {
Q_OBJECT
private:
QString _picsPath;
QList<CardInfo *> loadQueue;
QMutex mutex;
protected:
void run();
public:
PictureLoadingThread(QObject *parent);
~PictureLoadingThread();
void setPicsPath(const QString &path);
void loadImage(CardInfo *card);
signals:
void imageLoaded(CardInfo *card, const QImage &image);
};
class CardInfo : public QObject {
Q_OBJECT
private:
@ -85,6 +104,7 @@ public:
QPixmap *getPixmap(QSize size);
void clearPixmapCache();
void clearPixmapCacheMiss();
void imageLoaded(const QImage &image);
public slots:
void updatePixmapCache();
signals:
@ -102,6 +122,7 @@ protected:
bool downloadRunning;
bool loadSuccess;
CardInfo *noCard;
PictureLoadingThread *loadingThread;
private:
void loadCardsFromXml(QXmlStreamReader &xml);
void loadSetsFromXml(QXmlStreamReader &xml);
@ -120,6 +141,8 @@ public:
QStringList getAllColors() const;
QStringList getAllMainCardTypes() const;
bool getLoadSuccess() const { return loadSuccess; }
void cacheCardPixmaps(const QStringList &cardNames);
void loadImage(CardInfo *card);
public slots:
void clearPixmapCache();
bool loadCardDatabase(const QString &path);
@ -127,6 +150,7 @@ public slots:
private slots:
void picDownloadFinished(QNetworkReply *reply);
void picDownloadChanged();
void imageLoaded(CardInfo *card, QImage image);
};
#endif

View file

@ -1,29 +0,0 @@
#include <QProgressDialog>
#include "deck_picturecacher.h"
#include "decklist.h"
#include "carddatabase.h"
#include "main.h"
void Deck_PictureCacher::cacheHelper(InnerDecklistNode *item, QProgressDialog *progress)
{
for (int i = 0; i < item->size(); i++) {
DecklistCardNode *node = dynamic_cast<DecklistCardNode *>(item->at(i));
if (node) {
db->getCard(node->getName())->loadPixmap();
progress->setValue(progress->value() + 1);
} else
cacheHelper(dynamic_cast<InnerDecklistNode *>(item->at(i)), progress);
}
}
void Deck_PictureCacher::cachePictures(DeckList *deck, QWidget *parent)
{
int totalCards = deck->getRoot()->recursiveCount();
QProgressDialog progress(tr("Caching card pictures..."), QString(), 0, totalCards, parent);
progress.setMinimumDuration(1000);
progress.setWindowModality(Qt::WindowModal);
cacheHelper(deck->getRoot(), &progress);
}

View file

@ -1,19 +0,0 @@
#ifndef DECK_PICTURECACHER_H
#define DECK_PICTURECACHER_H
#include <QObject>
class InnerDecklistNode;
class QProgressDialog;
class DeckList;
class QWidget;
class Deck_PictureCacher : public QObject {
Q_OBJECT
private:
static void cacheHelper(InnerDecklistNode *item, QProgressDialog *progress);
public:
static void cachePictures(DeckList *deck, QWidget *parent);
};
#endif

View file

@ -18,7 +18,6 @@
#include "zoneviewwidget.h"
#include "deckview.h"
#include "decklist.h"
#include "deck_picturecacher.h"
#include "protocol_items.h"
#include "dlg_load_remote_deck.h"
#include "abstractclient.h"
@ -26,6 +25,7 @@
#include "arrowitem.h"
#include "main.h"
#include "settingscache.h"
#include "carddatabase.h"
ReadyStartButton::ReadyStartButton(QWidget *parent)
: QPushButton(parent), readyStart(false)
@ -131,7 +131,7 @@ void DeckViewContainer::deckSelectFinished(ProtocolResponse *r)
if (!resp)
return;
Deck_PictureCacher::cachePictures(resp->getDeck(), this);
db->cacheCardPixmaps(resp->getDeck()->getCardList());
deckView->setDeck(new DeckList(resp->getDeck()));
readyStartButton->setEnabled(true);
}
@ -508,7 +508,7 @@ void TabGame::eventGameStateChanged(Event_GameStateChanged *event, GameEventCont
}
player->processPlayerInfo(pl);
if (player->getLocal() && !pl->getDeck()->isEmpty()) {
Deck_PictureCacher::cachePictures(pl->getDeck(), this);
db->cacheCardPixmaps(pl->getDeck()->getCardList());
deckViewContainers.value(player->getId())->setDeck(new DeckList(pl->getDeck()));
}
}

View file

@ -22,7 +22,6 @@
#include "carddatabasemodel.h"
#include "decklistmodel.h"
#include "cardinfowidget.h"
#include "deck_picturecacher.h"
#include "dlg_cardsearch.h"
#include "dlg_load_deck_from_clipboard.h"
#include "main.h"
@ -467,7 +466,7 @@ void WndDeckEditor::setDeck(DeckList *_deck, const QString &_lastFileName, DeckL
deckView->expandAll();
setWindowModified(false);
Deck_PictureCacher::cachePictures(_deck, this);
db->cacheCardPixmaps(_deck->getCardList());
deckView->expandAll();
setWindowModified(false);
}

View file

@ -468,6 +468,24 @@ void DeckList::cleanList()
setComments();
}
void DeckList::getCardListHelper(InnerDecklistNode *item, QSet<QString> &result) const
{
for (int i = 0; i < item->size(); ++i) {
DecklistCardNode *node = dynamic_cast<DecklistCardNode *>(item->at(i));
if (node)
result.insert(node->getName());
else
getCardListHelper(dynamic_cast<InnerDecklistNode *>(item->at(i)), result);
}
}
QStringList DeckList::getCardList() const
{
QSet<QString> result;
getCardListHelper(root, result);
return result.toList();
}
DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zoneName)
{
InnerDecklistNode *zoneNode = dynamic_cast<InnerDecklistNode *>(root->findChild(zoneName));

View file

@ -6,6 +6,7 @@
#include <QPair>
#include <QObject>
#include <QStringList>
#include <QSet>
#include "serializable_item.h"
class CardDatabase;
@ -115,6 +116,7 @@ private:
InnerDecklistNode *currentZone;
SideboardPlan *currentSideboardPlan;
QString currentElementText;
void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
signals:
void deckLoaded();
public slots:
@ -149,6 +151,7 @@ public:
void cleanList();
bool isEmpty() const { return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty(); }
QStringList getCardList() const;
InnerDecklistNode *getRoot() const { return root; }
DecklistCardNode *addCard(const QString &cardName, const QString &zoneName);