diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index d3e826a9..06dbc5f5 100644 --- a/cockatrice/cockatrice.pro +++ b/cockatrice/cockatrice.pro @@ -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 \ diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 1087af1b..374dd864 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -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,36 +175,24 @@ 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(); - - 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()) - db->startPicDownload(this); + db->loadImage(this); return pixmap; } +void CardInfo::imageLoaded(const QImage &image) +{ + if (!image.isNull()) { + *pixmap = QPixmap::fromImage(image); + emit pixmapUpdated(); + } else if (settingsCache->getPicDownload()) + db->startPicDownload(this); +} + QPixmap *CardInfo::getPixmap(QSize size) { qDebug(QString("CardInfo::getPixmap(%1, %2) for %3").arg(size.width()).arg(size.height()).arg(getName()).toLatin1()); @@ -243,6 +287,11 @@ CardDatabase::CardDatabase(QObject *parent) connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *))); 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 @@ -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); +} \ No newline at end of file diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index 16822a8e..10e62aa5 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include class CardDatabase; class CardInfo; @@ -35,6 +37,23 @@ public: void sortByKey(); }; +class PictureLoadingThread : public QThread { + Q_OBJECT +private: + QString _picsPath; + QList 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 diff --git a/cockatrice/src/deck_picturecacher.cpp b/cockatrice/src/deck_picturecacher.cpp deleted file mode 100644 index 8bd5f38e..00000000 --- a/cockatrice/src/deck_picturecacher.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#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(item->at(i)); - if (node) { - db->getCard(node->getName())->loadPixmap(); - progress->setValue(progress->value() + 1); - } else - cacheHelper(dynamic_cast(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); -} - \ No newline at end of file diff --git a/cockatrice/src/deck_picturecacher.h b/cockatrice/src/deck_picturecacher.h deleted file mode 100644 index e278e508..00000000 --- a/cockatrice/src/deck_picturecacher.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef DECK_PICTURECACHER_H -#define DECK_PICTURECACHER_H - -#include - -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 diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index 13719e78..7f0e9e95 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -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())); } } diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index e9f2f44e..b72105a8 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -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" @@ -466,8 +465,8 @@ void WndDeckEditor::setDeck(DeckList *_deck, const QString &_lastFileName, DeckL deckModel->sort(1); deckView->expandAll(); setWindowModified(false); - - Deck_PictureCacher::cachePictures(_deck, this); + + db->cacheCardPixmaps(_deck->getCardList()); deckView->expandAll(); setWindowModified(false); } diff --git a/common/decklist.cpp b/common/decklist.cpp index 1e7e0b07..9d69b5df 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -468,6 +468,24 @@ void DeckList::cleanList() setComments(); } +void DeckList::getCardListHelper(InnerDecklistNode *item, QSet &result) const +{ + for (int i = 0; i < item->size(); ++i) { + DecklistCardNode *node = dynamic_cast(item->at(i)); + if (node) + result.insert(node->getName()); + else + getCardListHelper(dynamic_cast(item->at(i)), result); + } +} + +QStringList DeckList::getCardList() const +{ + QSet result; + getCardListHelper(root, result); + return result.toList(); +} + DecklistCardNode *DeckList::addCard(const QString &cardName, const QString &zoneName) { InnerDecklistNode *zoneNode = dynamic_cast(root->findChild(zoneName)); diff --git a/common/decklist.h b/common/decklist.h index d54959e2..37942174 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "serializable_item.h" class CardDatabase; @@ -115,6 +116,7 @@ private: InnerDecklistNode *currentZone; SideboardPlan *currentSideboardPlan; QString currentElementText; + void getCardListHelper(InnerDecklistNode *node, QSet &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);