Reimplemented PictureLoader as a singleton

* Removed remaining picture handling from card database and cardinfo
 * removed the “noCard object” hack
This commit is contained in:
Fabio Bas 2015-08-22 17:22:08 +02:00
parent 8125358052
commit f6c7f3355f
20 changed files with 654 additions and 704 deletions

View file

@ -95,6 +95,7 @@ SET(cockatrice_SOURCES
src/qt-json/json.cpp src/qt-json/json.cpp
src/soundengine.cpp src/soundengine.cpp
src/pending_command.cpp src/pending_command.cpp
src/pictureloader.cpp
src/shortcutssettings.cpp src/shortcutssettings.cpp
src/sequenceEdit/sequenceedit.cpp src/sequenceEdit/sequenceedit.cpp
src/sequenceEdit/shortcutstab.cpp src/sequenceEdit/shortcutstab.cpp

View file

@ -9,6 +9,7 @@
#include "carddatabase.h" #include "carddatabase.h"
#include "cardinfowidget.h" #include "cardinfowidget.h"
#include "abstractcarditem.h" #include "abstractcarditem.h"
#include "pictureloader.h"
#include "settingscache.h" #include "settingscache.h"
#include "main.h" #include "main.h"
#include "gamescene.h" #include "gamescene.h"
@ -45,7 +46,8 @@ void AbstractCardItem::pixmapUpdated()
void AbstractCardItem::cardInfoUpdated() void AbstractCardItem::cardInfoUpdated()
{ {
info = db->getCard(name); info = db->getCard(name);
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated())); if(info)
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
} }
void AbstractCardItem::setRealZValue(qreal _zValue) void AbstractCardItem::setRealZValue(qreal _zValue)
@ -93,7 +95,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
QPixmap translatedPixmap; QPixmap translatedPixmap;
// don't even spend time trying to load the picture if our size is too small // don't even spend time trying to load the picture if our size is too small
if(translatedSize.width() > 10) if(translatedSize.width() > 10)
imageSource->getPixmap(translatedSize.toSize(), translatedPixmap); PictureLoader::getPixmap(translatedPixmap, imageSource, translatedSize.toSize());
painter->save(); painter->save();
QColor bgColor = Qt::transparent; QColor bgColor = Qt::transparent;
@ -191,10 +193,12 @@ void AbstractCardItem::setName(const QString &_name)
return; return;
emit deleteCardInfoPopup(name); emit deleteCardInfoPopup(name);
disconnect(info, 0, this, 0); if(info)
disconnect(info, 0, this, 0);
name = _name; name = _name;
info = db->getCard(name); info = db->getCard(name);
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated())); if(info)
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
update(); update();
} }

View file

@ -1,20 +1,16 @@
#include "carddatabase.h" #include "carddatabase.h"
#include "pictureloader.h"
#include "settingscache.h" #include "settingscache.h"
#include "thememanager.h" #include "thememanager.h"
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QDebug>
#include <QDir> #include <QDir>
#include <QDirIterator> #include <QDirIterator>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
#include <QPainter> #include <QSettings>
#include <QUrl>
#include <QSet>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDebug>
#include <QImageReader>
#include <QMessageBox> #include <QMessageBox>
const int CardDatabase::versionNeeded = 3; const int CardDatabase::versionNeeded = 3;
@ -88,38 +84,6 @@ void SetList::sortByKey()
qSort(begin(), end(), KeyCompareFunctor()); qSort(begin(), end(), KeyCompareFunctor());
} }
class SetList::EnabledAndKeyCompareFunctor {
public:
inline bool operator()(CardSet *a, CardSet *b) const
{
if(a->getEnabled())
{
if(b->getEnabled())
{
// both enabled: sort by key
return a->getSortKey() < b->getSortKey();
} else {
// only a enabled
return true;
}
} else {
if(b->getEnabled())
{
// only b enabled
return false;
} else {
// both disabled: sort by key
return a->getSortKey() < b->getSortKey();
}
}
}
};
void SetList::sortByEnabledAndKey()
{
qSort(begin(), end(), EnabledAndKeyCompareFunctor());
}
int SetList::getEnabledSetsNum() int SetList::getEnabledSetsNum()
{ {
int num=0; int num=0;
@ -195,334 +159,6 @@ void SetList::guessSortKeys()
} }
} }
PictureToLoad::PictureToLoad(CardInfo *_card, bool _hq)
: card(_card), setIndex(0), hq(_hq)
{
if (card) {
sortedSets = card->getSets();
sortedSets.sortByEnabledAndKey();
}
}
bool PictureToLoad::nextSet()
{
if (setIndex == sortedSets.size() - 1)
return false;
++setIndex;
return true;
}
QString PictureToLoad::getSetName() const
{
if (setIndex < sortedSets.size())
return sortedSets[setIndex]->getCorrectedShortName();
else
return QString("");
}
CardSet *PictureToLoad::getCurrentSet() const
{
if (setIndex < sortedSets.size())
return sortedSets[setIndex];
else
return 0;
}
QStringList PictureLoader::md5Blacklist = QStringList()
<< "db0c48db407a907c16ade38de048a441"; // card back returned by gatherer when card is not found
PictureLoader::PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent)
: QObject(parent),
_picsPath(__picsPath), picDownload(_picDownload), picDownloadHq(_picDownloadHq),
downloadRunning(false), loadQueueRunning(false)
{
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
networkManager = new QNetworkAccessManager(this);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
}
PictureLoader::~PictureLoader()
{
// This does not work with the destroyed() signal as this destructor is called after the main event loop is done.
thread()->quit();
}
void PictureLoader::processLoadQueue()
{
if (loadQueueRunning)
return;
loadQueueRunning = true;
forever {
mutex.lock();
if (loadQueue.isEmpty()) {
mutex.unlock();
loadQueueRunning = false;
return;
}
cardBeingLoaded = loadQueue.takeFirst();
mutex.unlock();
QString setName = cardBeingLoaded.getSetName();
QString correctedCardname = cardBeingLoaded.getCard()->getCorrectedName();
qDebug() << "Trying to load picture (set: " << setName << " card: " << correctedCardname << ")";
//The list of paths to the folders in which to search for images
QList<QString> picsPaths = QList<QString>() << _picsPath + "/CUSTOM/" + correctedCardname;
if(!setName.isEmpty())
{
picsPaths << _picsPath + "/" + setName + "/" + correctedCardname
<< _picsPath + "/downloadedPics/" + setName + "/" + correctedCardname;
}
QImage image;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
bool found = false;
//Iterates through the list of paths, searching for images with the desired name with any QImageReader-supported extension
for (int i = 0; i < picsPaths.length() && !found; i ++) {
imgReader.setFileName(picsPaths.at(i));
if (imgReader.read(&image)) {
qDebug() << "Picture found on disk (set: " << setName << " card: " << correctedCardname << ")";
emit imageLoaded(cardBeingLoaded.getCard(), image);
found = true;
break;
}
imgReader.setFileName(picsPaths.at(i) + ".full");
if (imgReader.read(&image)) {
qDebug() << "Picture.full found on disk (set: " << setName << " card: " << correctedCardname << ")";
emit imageLoaded(cardBeingLoaded.getCard(), image);
found = true;
}
}
if (!found) {
if (picDownload) {
qDebug() << "Picture NOT found, trying to download (set: " << setName << " card: " << correctedCardname << ")";
cardsToDownload.append(cardBeingLoaded);
cardBeingLoaded=0;
if (!downloadRunning)
startNextPicDownload();
} else {
if (cardBeingLoaded.nextSet())
{
qDebug() << "Picture NOT found and download disabled, moving to next set (newset: " << setName << " card: " << correctedCardname << ")";
mutex.lock();
loadQueue.prepend(cardBeingLoaded);
cardBeingLoaded=0;
mutex.unlock();
} else {
qDebug() << "Picture NOT found, download disabled, no more sets to try: BAILING OUT (oldset: " << setName << " card: " << correctedCardname << ")";
emit imageLoaded(cardBeingLoaded.getCard(), QImage());
}
}
}
}
}
QString PictureLoader::getPicUrl()
{
if (!picDownload) return QString("");
CardInfo *card = cardBeingDownloaded.getCard();
CardSet *set=cardBeingDownloaded.getCurrentSet();
QString picUrl = QString("");
// if sets have been defined for the card, they can contain custom picUrls
if(set)
{
// first check if Hq is enabled and a custom Hq card url exists in cards.xml
if(picDownloadHq)
{
picUrl = card->getCustomPicURLHq(set->getShortName());
if (!picUrl.isEmpty())
return picUrl;
}
// then, test for a custom, non-Hq card url in cards.xml
picUrl = card->getCustomPicURL(set->getShortName());
if (!picUrl.isEmpty())
return picUrl;
}
// if a card has a muid, use the default url; if not, use the fallback
int muid = set ? card->getMuId(set->getShortName()) : 0;
if(muid)
picUrl = picDownloadHq ? settingsCache->getPicUrlHq() : settingsCache->getPicUrl();
else
picUrl = picDownloadHq ? settingsCache->getPicUrlHqFallback() : settingsCache->getPicUrlFallback();
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
picUrl.replace("!name_lower!", QUrl::toPercentEncoding(card->getCorrectedName().toLower()));
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(muid)));
if (set)
{
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName()));
picUrl.replace("!setcode_lower!", QUrl::toPercentEncoding(set->getShortName().toLower()));
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
picUrl.replace("!setname_lower!", QUrl::toPercentEncoding(set->getLongName().toLower()));
}
if (
picUrl.contains("!name!") ||
picUrl.contains("!name_lower!") ||
picUrl.contains("!setcode!") ||
picUrl.contains("!setcode_lower!") ||
picUrl.contains("!setname!") ||
picUrl.contains("!setname_lower!") ||
picUrl.contains("!cardid!")
)
{
qDebug() << "Insufficient card data to download" << card->getName() << "Url:" << picUrl;
return QString("");
}
return picUrl;
}
void PictureLoader::startNextPicDownload()
{
if (cardsToDownload.isEmpty()) {
cardBeingDownloaded = 0;
downloadRunning = false;
return;
}
downloadRunning = true;
cardBeingDownloaded = cardsToDownload.takeFirst();
QString picUrl = getPicUrl();
if (picUrl.isEmpty()) {
downloadRunning = false;
picDownloadFailed();
} else {
QUrl url(picUrl);
QNetworkRequest req(url);
qDebug() << "starting picture download:" << cardBeingDownloaded.getCard()->getName() << "Url:" << req.url();
networkManager->get(req);
}
}
void PictureLoader::picDownloadFailed()
{
if (cardBeingDownloaded.nextSet())
{
qDebug() << "Picture NOT found, download failed, moving to next set (newset: " << cardBeingDownloaded.getSetName() << " card: " << cardBeingDownloaded.getCard()->getCorrectedName() << ")";
mutex.lock();
loadQueue.prepend(cardBeingDownloaded);
mutex.unlock();
emit startLoadQueue();
} else {
qDebug() << "Picture NOT found, download failed, no more sets to try: BAILING OUT (oldset: " << cardBeingDownloaded.getSetName() << " card: " << cardBeingDownloaded.getCard()->getCorrectedName() << ")";
cardBeingDownloaded = 0;
emit imageLoaded(cardBeingDownloaded.getCard(), QImage());
}
}
void PictureLoader::picDownloadFinished(QNetworkReply *reply)
{
QString picsPath = _picsPath;
if (reply->error()) {
qDebug() << "Download failed:" << reply->errorString();
}
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302) {
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QNetworkRequest req(redirectUrl);
qDebug() << "following redirect:" << cardBeingDownloaded.getCard()->getName() << "Url:" << req.url();
networkManager->get(req);
return;
}
const QByteArray &picData = reply->peek(reply->size()); //peek is used to keep the data in the buffer for use by QImageReader
// check if the image is blacklisted
QString md5sum = QCryptographicHash::hash(picData, QCryptographicHash::Md5).toHex();
if(md5Blacklist.contains(md5sum))
{
qDebug() << "Picture downloaded, but blacklisted (" << md5sum << "), will consider it as not found";
picDownloadFailed();
reply->deleteLater();
startNextPicDownload();
return;
}
QImage testImage;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setDevice(reply);
QString extension = "." + imgReader.format(); //the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the QImageReader buffer
if (extension == ".jpeg")
extension = ".jpg";
if (imgReader.read(&testImage)) {
QString setName = cardBeingDownloaded.getSetName();
if(!setName.isEmpty())
{
if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
qDebug() << picsPath + "/downloadedPics/" + setName + " could not be created.";
return;
}
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" + cardBeingDownloaded.getCard()->getCorrectedName() + extension);
if (!newPic.open(QIODevice::WriteOnly))
return;
newPic.write(picData);
newPic.close();
}
emit imageLoaded(cardBeingDownloaded.getCard(), testImage);
} else {
picDownloadFailed();
}
reply->deleteLater();
startNextPicDownload();
}
void PictureLoader::loadImage(CardInfo *card)
{
QMutexLocker locker(&mutex);
// avoid queueing the same card more than once
if(card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard())
return;
foreach(PictureToLoad pic, loadQueue)
{
if(pic.getCard() == card)
return;
}
loadQueue.append(PictureToLoad(card));
emit startLoadQueue();
}
void PictureLoader::setPicsPath(const QString &path)
{
QMutexLocker locker(&mutex);
_picsPath = path;
}
void PictureLoader::setPicDownload(bool _picDownload)
{
QMutexLocker locker(&mutex);
picDownload = _picDownload;
}
void PictureLoader::setPicDownloadHq(bool _picDownloadHq)
{
QMutexLocker locker(&mutex);
picDownloadHq = _picDownloadHq;
}
CardInfo::CardInfo(CardDatabase *_db, CardInfo::CardInfo(CardDatabase *_db,
const QString &_name, const QString &_name,
bool _isToken, bool _isToken,
@ -539,7 +175,6 @@ CardInfo::CardInfo(CardDatabase *_db,
int _tableRow, int _tableRow,
const SetList &_sets, const SetList &_sets,
const QStringMap &_customPicURLs, const QStringMap &_customPicURLs,
const QStringMap &_customPicURLsHq,
MuidMap _muIds MuidMap _muIds
) )
: db(_db), : db(_db),
@ -556,7 +191,6 @@ CardInfo::CardInfo(CardDatabase *_db,
upsideDownArt(_upsideDownArt), upsideDownArt(_upsideDownArt),
loyalty(_loyalty), loyalty(_loyalty),
customPicURLs(_customPicURLs), customPicURLs(_customPicURLs),
customPicURLsHq(_customPicURLsHq),
muIds(_muIds), muIds(_muIds),
cipt(_cipt), cipt(_cipt),
tableRow(_tableRow) tableRow(_tableRow)
@ -570,7 +204,7 @@ CardInfo::CardInfo(CardDatabase *_db,
CardInfo::~CardInfo() CardInfo::~CardInfo()
{ {
clearPixmapCache(); PictureLoader::clearPixmapCache(this);
} }
QString CardInfo::getMainCardType() const QString CardInfo::getMainCardType() const
@ -617,82 +251,6 @@ void CardInfo::addToSet(CardSet *set)
sets << set; sets << set;
} }
void CardInfo::loadPixmap(QPixmap &pixmap)
{
if(QPixmapCache::find(pixmapCacheKey, &pixmap))
return;
pixmap = QPixmap();
if (getName().isEmpty()) {
pixmap = QPixmap("theme:cardback");
return;
}
db->loadImage(this);
}
void CardInfo::imageLoaded(const QImage &image)
{
if (!image.isNull()) {
if(upsideDownArt)
{
QImage mirrorImage = image.mirrored(true, true);
QPixmapCache::insert(pixmapCacheKey, QPixmap::fromImage(mirrorImage));
} else {
QPixmapCache::insert(pixmapCacheKey, QPixmap::fromImage(image));
}
emit pixmapUpdated();
}
}
void CardInfo::getPixmap(QSize size, QPixmap &pixmap)
{
QString key = QLatin1String("card_") + name + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
if(QPixmapCache::find(key, &pixmap))
return;
QPixmap bigPixmap;
loadPixmap(bigPixmap);
if (bigPixmap.isNull()) {
if (getName().isEmpty()) {
pixmap = pixmap = QPixmap("theme:cardback");
} else {
pixmap = QPixmap(); // null
return;
}
}
pixmap = bigPixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(key, pixmap);
}
void CardInfo::clearPixmapCache()
{
//qDebug() << "Deleting pixmap for" << name;
QPixmapCache::remove(pixmapCacheKey);
}
void CardInfo::clearPixmapCacheMiss()
{
QPixmap pixmap;
if(!QPixmapCache::find(pixmapCacheKey, &pixmap))
return;
if (pixmap.isNull())
clearPixmapCache();
}
void CardInfo::updatePixmapCache()
{
qDebug() << "Updating pixmap cache for" << name;
clearPixmapCache();
QPixmap tmp;
loadPixmap(tmp);
emit pixmapUpdated();
}
QString CardInfo::simplifyName(const QString &name) { QString CardInfo::simplifyName(const QString &name) {
QString simpleName(name); QString simpleName(name);
@ -731,10 +289,6 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
if(!tmpString.isEmpty()) if(!tmpString.isEmpty())
xml.writeAttribute("picURL", tmpString); xml.writeAttribute("picURL", tmpString);
tmpString = info->getCustomPicURLHq(tmpSet);
if(!tmpString.isEmpty())
xml.writeAttribute("picURLHq", tmpString);
xml.writeCharacters(tmpSet); xml.writeCharacters(tmpSet);
xml.writeEndElement(); xml.writeEndElement();
} }
@ -767,37 +321,18 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
} }
CardDatabase::CardDatabase(QObject *parent) CardDatabase::CardDatabase(QObject *parent)
: QObject(parent), noCard(0), loadStatus(NotLoaded) : QObject(parent), loadStatus(NotLoaded)
{ {
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase())); connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase()));
connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase())); connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
connect(settingsCache, SIGNAL(picDownloadHqChanged()), this, SLOT(picDownloadHqChanged()));
loadCardDatabase(); loadCardDatabase();
loadTokenDatabase(); loadTokenDatabase();
pictureLoaderThread = new QThread;
pictureLoader = new PictureLoader(settingsCache->getPicsPath(), settingsCache->getPicDownload(), settingsCache->getPicDownloadHq());
pictureLoader->moveToThread(pictureLoaderThread);
connect(pictureLoader, SIGNAL(imageLoaded(CardInfo *, const QImage &)), this, SLOT(imageLoaded(CardInfo *, const QImage &)));
pictureLoaderThread->start(QThread::LowPriority);
noCard = new CardInfo(this);
QPixmap tmp;
noCard->loadPixmap(tmp); // cache pixmap for card back
connect(themeManager, SIGNAL(themeChanged()), noCard, SLOT(updatePixmapCache()));
} }
CardDatabase::~CardDatabase() CardDatabase::~CardDatabase()
{ {
clear(); clear();
delete noCard;
pictureLoader->deleteLater();
pictureLoaderThread->wait();
delete pictureLoaderThread;
} }
void CardDatabase::clear() void CardDatabase::clear()
@ -839,6 +374,15 @@ CardInfo *CardDatabase::getCard(const QString &cardName, bool createIfNotFound)
return getCardFromMap(cards, cardName, createIfNotFound); return getCardFromMap(cards, cardName, createIfNotFound);
} }
QList<CardInfo *> CardDatabase::getCards(const QStringList &cardNames)
{
QList<CardInfo *> cardInfos;
foreach(QString cardName, cardNames)
cardInfos.append(getCardFromMap(cards, cardName, false));
return cardInfos;
}
CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName, bool createIfNotFound) { CardInfo *CardDatabase::getCardBySimpleName(const QString &cardName, bool createIfNotFound) {
QString simpleName = CardInfo::simplifyName(cardName); QString simpleName = CardInfo::simplifyName(cardName);
return getCardFromMap(simpleNameCards, simpleName, createIfNotFound); return getCardFromMap(simpleNameCards, simpleName, createIfNotFound);
@ -866,21 +410,6 @@ SetList CardDatabase::getSetList() const
return result; return result;
} }
void CardDatabase::clearPixmapCache()
{
// This also clears the cards in simpleNameCards since they point to the
// same object.
QHashIterator<QString, CardInfo *> i(cards);
while (i.hasNext()) {
i.next();
i.value()->clearPixmapCache();
}
if (noCard)
noCard->clearPixmapCache();
QPixmapCache::clear();
}
void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml) void CardDatabase::loadSetsFromXml(QXmlStreamReader &xml)
{ {
while (!xml.atEnd()) { while (!xml.atEnd()) {
@ -918,7 +447,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
if (xml.name() == "card") { if (xml.name() == "card") {
QString name, manacost, cmc, type, pt, text; QString name, manacost, cmc, type, pt, text;
QStringList colors, relatedCards; QStringList colors, relatedCards;
QStringMap customPicURLs, customPicURLsHq; QStringMap customPicURLs;
MuidMap muids; MuidMap muids;
SetList sets; SetList sets;
int tableRow = 0; int tableRow = 0;
@ -951,9 +480,6 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
if (attrs.hasAttribute("picURL")) { if (attrs.hasAttribute("picURL")) {
customPicURLs[setName] = attrs.value("picURL").toString(); customPicURLs[setName] = attrs.value("picURL").toString();
} }
if (attrs.hasAttribute("picURLHq")) {
customPicURLsHq[setName] = attrs.value("picURLHq").toString();
}
} else if (xml.name() == "color") } else if (xml.name() == "color")
colors << xml.readElementText(); colors << xml.readElementText();
else if (xml.name() == "related") else if (xml.name() == "related")
@ -971,24 +497,24 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
} }
if (isToken == tokens) { if (isToken == tokens) {
addCard(new CardInfo(this, name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, customPicURLsHq, muids)); addCard(new CardInfo(this, name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, muids));
} }
} }
} }
} }
CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound) { CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &cardName, bool createIfNotFound) {
if (cardName.isEmpty()) if (cardMap.contains(cardName))
return noCard;
else if (cardMap.contains(cardName))
return cardMap.value(cardName); return cardMap.value(cardName);
else if (createIfNotFound) {
if (createIfNotFound) {
CardInfo *newCard = new CardInfo(this, cardName, true); CardInfo *newCard = new CardInfo(this, cardName, true);
newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME)); newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME));
cardMap.insert(cardName, newCard); cardMap.insert(cardName, newCard);
return newCard; return newCard;
} else }
return 0;
return 0;
} }
LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens) LoadStatus CardDatabase::loadFromFile(const QString &fileName, bool tokens)
@ -1061,26 +587,6 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
return true; return true;
} }
void CardDatabase::picDownloadChanged()
{
pictureLoader->setPicDownload(settingsCache->getPicDownload());
if (settingsCache->getPicDownload()) {
QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext())
cardIterator.next().value()->clearPixmapCacheMiss();
}
}
void CardDatabase::picDownloadHqChanged()
{
pictureLoader->setPicDownloadHq(settingsCache->getPicDownloadHq());
if (settingsCache->getPicDownloadHq()) {
QHashIterator<QString, CardInfo *> cardIterator(cards);
while (cardIterator.hasNext())
cardIterator.next().value()->clearPixmapCacheMiss();
}
}
void CardDatabase::emitCardListChanged() void CardDatabase::emitCardListChanged()
{ {
emit cardListChanged(); emit cardListChanged();
@ -1159,31 +665,6 @@ QStringList CardDatabase::getAllMainCardTypes() const
return types.toList(); return types.toList();
} }
void CardDatabase::cacheCardPixmaps(const QStringList &cardNames)
{
QPixmap tmp;
// never cache more than 300 cards at once for a single deck
int max = qMin(cardNames.size(), 300);
for (int i = 0; i < max; ++i)
getCard(cardNames[i])->loadPixmap(tmp);
}
void CardDatabase::loadImage(CardInfo *card)
{
pictureLoader->loadImage(card);
}
void CardDatabase::imageLoaded(CardInfo *card, QImage image)
{
card->imageLoaded(image);
}
void CardDatabase::picsPathChanged()
{
pictureLoader->setPicsPath(settingsCache->getPicsPath());
clearPixmapCache();
}
void CardDatabase::checkUnknownSets() void CardDatabase::checkUnknownSets()
{ {
SetList sets = getSetList(); SetList sets = getSetList();

View file

@ -8,17 +8,9 @@
#include <QDataStream> #include <QDataStream>
#include <QList> #include <QList>
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QNetworkRequest>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QPixmapCache>
class CardDatabase; class CardDatabase;
class CardInfo; class CardInfo;
class QNetworkAccessManager;
class QNetworkReply;
class QNetworkRequest;
typedef QMap<QString, QString> QStringMap; typedef QMap<QString, QString> QStringMap;
@ -55,9 +47,7 @@ public:
class SetList : public QList<CardSet *> { class SetList : public QList<CardSet *> {
private: private:
class KeyCompareFunctor; class KeyCompareFunctor;
class EnabledAndKeyCompareFunctor;
public: public:
void sortByEnabledAndKey();
void sortByKey(); void sortByKey();
void guessSortKeys(); void guessSortKeys();
void enableAllUnknown(); void enableAllUnknown();
@ -67,53 +57,6 @@ public:
int getUnknownSetsNum(); int getUnknownSetsNum();
}; };
class PictureToLoad {
private:
CardInfo *card;
SetList sortedSets;
int setIndex;
bool hq;
public:
PictureToLoad(CardInfo *_card = 0, bool _hq = true);
CardInfo *getCard() const { return card; }
CardSet *getCurrentSet() const;
QString getSetName() const;
bool nextSet();
bool getHq() const { return hq; }
void setHq(bool _hq) { hq = _hq; }
};
class PictureLoader : public QObject {
Q_OBJECT
private:
QString _picsPath;
QList<PictureToLoad> loadQueue;
QMutex mutex;
QNetworkAccessManager *networkManager;
QList<PictureToLoad> cardsToDownload;
PictureToLoad cardBeingLoaded;
PictureToLoad cardBeingDownloaded;
bool picDownload, picDownloadHq, downloadRunning, loadQueueRunning;
void startNextPicDownload();
QString getPicUrl();
static QStringList md5Blacklist;
public:
PictureLoader(const QString &__picsPath, bool _picDownload, bool _picDownloadHq, QObject *parent = 0);
~PictureLoader();
void setPicsPath(const QString &path);
void setPicDownload(bool _picDownload);
void setPicDownloadHq(bool _picDownloadHq);
void loadImage(CardInfo *card);
private slots:
void picDownloadFinished(QNetworkReply *reply);
void picDownloadFailed();
public slots:
void processLoadQueue();
signals:
void startLoadQueue();
void imageLoaded(CardInfo *card, const QImage &image);
};
class CardInfo : public QObject { class CardInfo : public QObject {
Q_OBJECT Q_OBJECT
private: private:
@ -138,7 +81,7 @@ private:
QStringList relatedCards; QStringList relatedCards;
bool upsideDownArt; bool upsideDownArt;
int loyalty; int loyalty;
QStringMap customPicURLs, customPicURLsHq; QStringMap customPicURLs;
MuidMap muIds; MuidMap muIds;
bool cipt; bool cipt;
int tableRow; int tableRow;
@ -160,7 +103,6 @@ public:
int _tableRow = 0, int _tableRow = 0,
const SetList &_sets = SetList(), const SetList &_sets = SetList(),
const QStringMap &_customPicURLs = QStringMap(), const QStringMap &_customPicURLs = QStringMap(),
const QStringMap &_customPicURLsHq = QStringMap(),
MuidMap muids = MuidMap() MuidMap muids = MuidMap()
); );
~CardInfo(); ~CardInfo();
@ -173,6 +115,7 @@ public:
const QString &getCardType() const { return cardtype; } const QString &getCardType() const { return cardtype; }
const QString &getPowTough() const { return powtough; } const QString &getPowTough() const { return powtough; }
const QString &getText() const { return text; } const QString &getText() const { return text; }
const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
const int &getLoyalty() const { return loyalty; } const int &getLoyalty() const { return loyalty; }
bool getCipt() const { return cipt; } bool getCipt() const { return cipt; }
void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); } void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); }
@ -185,7 +128,6 @@ public:
const QStringList &getRelatedCards() const { return relatedCards; } const QStringList &getRelatedCards() const { return relatedCards; }
bool getUpsideDownArt() const { return upsideDownArt; } bool getUpsideDownArt() const { return upsideDownArt; }
QString getCustomPicURL(const QString &set) const { return customPicURLs.value(set); } QString getCustomPicURL(const QString &set) const { return customPicURLs.value(set); }
QString getCustomPicURLHq(const QString &set) const { return customPicURLsHq.value(set); }
int getMuId(const QString &set) const { return muIds.value(set); } int getMuId(const QString &set) const { return muIds.value(set); }
QString getMainCardType() const; QString getMainCardType() const;
QString getCorrectedName() const; QString getCorrectedName() const;
@ -193,22 +135,14 @@ public:
void setTableRow(int _tableRow) { tableRow = _tableRow; } void setTableRow(int _tableRow) { tableRow = _tableRow; }
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); } void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); } void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set, _customPicURL); }
void setCustomPicURLHq(const QString &_set, const QString &_customPicURL) { customPicURLsHq.insert(_set, _customPicURL); }
void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); } void setMuId(const QString &_set, const int &_muId) { muIds.insert(_set, _muId); }
void addToSet(CardSet *set); void addToSet(CardSet *set);
void loadPixmap(QPixmap &pixmap);
void getPixmap(QSize size, QPixmap &pixmap);
void clearPixmapCache();
void clearPixmapCacheMiss();
void imageLoaded(const QImage &image);
/** /**
* Simplify a name to have no punctuation and lowercase all letters, for * Simplify a name to have no punctuation and lowercase all letters, for
* less strict name-matching. * less strict name-matching.
*/ */
static QString simplifyName(const QString &name); static QString simplifyName(const QString &name);
public slots:
void updatePixmapCache();
signals: signals:
void pixmapUpdated(); void pixmapUpdated();
void cardInfoChanged(CardInfo *card); void cardInfoChanged(CardInfo *card);
@ -237,10 +171,6 @@ protected:
*/ */
SetNameMap sets; SetNameMap sets;
CardInfo *noCard;
QThread *pictureLoaderThread;
PictureLoader *pictureLoader;
LoadStatus loadStatus; LoadStatus loadStatus;
bool detectedFirstRun; bool detectedFirstRun;
private: private:
@ -258,13 +188,14 @@ public:
void clear(); void clear();
void addCard(CardInfo *card); void addCard(CardInfo *card);
void removeCard(CardInfo *card); void removeCard(CardInfo *card);
CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = true); CardInfo *getCard(const QString &cardName = QString(), bool createIfNotFound = false);
QList <CardInfo *> getCards(const QStringList &cardNames);
/* /*
* Get a card by its simple name. The name will be simplified in this * Get a card by its simple name. The name will be simplified in this
* function, so you don't need to simplify it beforehand. * function, so you don't need to simplify it beforehand.
*/ */
CardInfo *getCardBySimpleName(const QString &cardName = QString(), bool createIfNotFound = true); CardInfo *getCardBySimpleName(const QString &cardName = QString(), bool createIfNotFound = false);
CardSet *getSet(const QString &setName); CardSet *getSet(const QString &setName);
QList<CardInfo *> getCardList() const { return cards.values(); } QList<CardInfo *> getCardList() const { return cards.values(); }
@ -275,20 +206,12 @@ public:
QStringList getAllMainCardTypes() const; QStringList getAllMainCardTypes() const;
LoadStatus getLoadStatus() const { return loadStatus; } LoadStatus getLoadStatus() const { return loadStatus; }
bool getLoadSuccess() const { return loadStatus == Ok; } bool getLoadSuccess() const { return loadStatus == Ok; }
void cacheCardPixmaps(const QStringList &cardNames);
void loadImage(CardInfo *card);
bool hasDetectedFirstRun(); bool hasDetectedFirstRun();
public slots: public slots:
void clearPixmapCache();
LoadStatus loadCardDatabase(const QString &path, bool tokens = false); LoadStatus loadCardDatabase(const QString &path, bool tokens = false);
void loadCustomCardDatabases(const QString &path); void loadCustomCardDatabases(const QString &path);
void emitCardListChanged(); void emitCardListChanged();
private slots: private slots:
void imageLoaded(CardInfo *card, QImage image);
void picDownloadChanged();
void picDownloadHqChanged();
void picsPathChanged();
void loadCardDatabase(); void loadCardDatabase();
void loadTokenDatabase(); void loadTokenDatabase();
signals: signals:

View file

@ -93,7 +93,8 @@ void CardFrame::setCard(CardInfo *card)
if (info) if (info)
disconnect(info, 0, this, 0); disconnect(info, 0, this, 0);
info = card; info = card;
connect(info, SIGNAL(destroyed()), this, SLOT(clear())); if(info)
connect(info, SIGNAL(destroyed()), this, SLOT(clear()));
text->setCard(info); text->setCard(info);
pic->setCard(info); pic->setCard(info);
} }

View file

@ -6,6 +6,7 @@
#include "carditem.h" #include "carditem.h"
#include "carddatabase.h" #include "carddatabase.h"
#include "pictureloader.h"
#include "main.h" #include "main.h"
CardInfoPicture::CardInfoPicture(QWidget *parent) CardInfoPicture::CardInfoPicture(QWidget *parent)
@ -21,7 +22,8 @@ void CardInfoPicture::setCard(CardInfo *card)
if (info) if (info)
disconnect(info, 0, this, 0); disconnect(info, 0, this, 0);
info = card; info = card;
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap())); if(info)
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
updatePixmap(); updatePixmap();
} }
@ -40,13 +42,13 @@ void CardInfoPicture::updatePixmap()
void CardInfoPicture::loadPixmap() void CardInfoPicture::loadPixmap()
{ {
if(info) if(info)
info->getPixmap(size(), resizedPixmap); PictureLoader::getPixmap(resizedPixmap, info, size());
else else
resizedPixmap = QPixmap(); resizedPixmap = QPixmap();
if (resizedPixmap.isNull()) if (resizedPixmap.isNull())
db->getCard()->getPixmap(size(), resizedPixmap); PictureLoader::getPixmap(resizedPixmap, db->getCard(), size());
} }
void CardInfoPicture::paintEvent(QPaintEvent *) void CardInfoPicture::paintEvent(QPaintEvent *)

View file

@ -53,13 +53,23 @@ CardInfoText::CardInfoText(QWidget *parent)
void CardInfoText::setCard(CardInfo *card) void CardInfoText::setCard(CardInfo *card)
{ {
nameLabel2->setText(card->getName()); if(card) {
manacostLabel2->setText(card->getManaCost()); nameLabel2->setText(card->getName());
colorLabel2->setText(card->getColors().join("")); manacostLabel2->setText(card->getManaCost());
cardtypeLabel2->setText(card->getCardType()); colorLabel2->setText(card->getColors().join(""));
powtoughLabel2->setText(card->getPowTough()); cardtypeLabel2->setText(card->getCardType());
loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString()); powtoughLabel2->setText(card->getPowTough());
textLabel->setText(card->getText()); loyaltyLabel2->setText(card->getLoyalty() > 0 ? QString::number(card->getLoyalty()) : QString());
textLabel->setText(card->getText());
} else {
nameLabel2->setText("");
manacostLabel2->setText("");
colorLabel2->setText("");
cardtypeLabel2->setText("");
powtoughLabel2->setText("");
loyaltyLabel2->setText("");
textLabel->setText("");
}
} }
void CardInfoText::retranslateUi() void CardInfoText::retranslateUi()

View file

@ -8,6 +8,7 @@
#include "cardinfowidget.h" #include "cardinfowidget.h"
#include "carditem.h" #include "carditem.h"
#include "carddatabase.h" #include "carddatabase.h"
#include "pictureloader.h"
#include "main.h" #include "main.h"
#include "settingscache.h" #include "settingscache.h"
@ -195,10 +196,10 @@ void CardInfoWidget::updatePixmap()
return; return;
QPixmap resizedPixmap; QPixmap resizedPixmap;
info->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio), resizedPixmap); PictureLoader::getPixmap(resizedPixmap, info, QSize(pixmapWidth, pixmapWidth * aspectRatio));
if (resizedPixmap.isNull()) if (resizedPixmap.isNull())
getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio), resizedPixmap); PictureLoader::getPixmap(resizedPixmap, getCard(), QSize(pixmapWidth, pixmapWidth * aspectRatio));
cardPicture->setPixmap(resizedPixmap); cardPicture->setPixmap(resizedPixmap);
} }

View file

@ -44,7 +44,6 @@ GeneralSettingsPage::GeneralSettingsPage()
} }
picDownloadCheckBox.setChecked(settingsCache->getPicDownload()); picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq());
updateNotificationCheckBox.setChecked(settingsCache->getNotifyAboutUpdates()); updateNotificationCheckBox.setChecked(settingsCache->getNotifyAboutUpdates());
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN); pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
@ -53,20 +52,22 @@ GeneralSettingsPage::GeneralSettingsPage()
pixmapCacheEdit.setSingleStep(64); pixmapCacheEdit.setSingleStep(64);
pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize()); pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize());
pixmapCacheEdit.setSuffix(" MB"); pixmapCacheEdit.setSuffix(" MB");
picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq());
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
highQualityURLEdit = new QLineEdit(settingsCache->getPicUrlHq()); defaultUrlEdit = new QLineEdit(settingsCache->getPicUrl());
highQualityURLEdit->setEnabled(settingsCache->getPicDownloadHq()); fallbackUrlEdit = new QLineEdit(settingsCache->getPicUrlFallback());
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked())); connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int))); connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int))); connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
connect(&picDownloadHqCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownloadHq(int)));
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int))); connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int)));
connect(&picDownloadHqCheckBox, SIGNAL(clicked(bool)), this, SLOT(setEnabledStatus(bool)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int))); connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int)));
connect(highQualityURLEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrlHq(QString))); connect(&picDownloadCheckBox, SIGNAL(clicked(bool)), this, SLOT(setEnabledStatus(bool)));
connect(defaultUrlEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrl(QString)));
connect(fallbackUrlEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrlFallback(QString)));
connect(&defaultUrlRestoreButton, SIGNAL(clicked()), this, SLOT(defaultUrlRestoreButtonClicked()));
connect(&fallbackUrlRestoreButton, SIGNAL(clicked()), this, SLOT(fallbackUrlRestoreButtonClicked()));
setEnabledStatus(settingsCache->getPicDownload());
QGridLayout *personalGrid = new QGridLayout; QGridLayout *personalGrid = new QGridLayout;
personalGrid->addWidget(&languageLabel, 0, 0); personalGrid->addWidget(&languageLabel, 0, 0);
@ -74,15 +75,18 @@ GeneralSettingsPage::GeneralSettingsPage()
personalGrid->addWidget(&pixmapCacheLabel, 1, 0); personalGrid->addWidget(&pixmapCacheLabel, 1, 0);
personalGrid->addWidget(&pixmapCacheEdit, 1, 1); personalGrid->addWidget(&pixmapCacheEdit, 1, 1);
personalGrid->addWidget(&updateNotificationCheckBox, 2, 0); personalGrid->addWidget(&updateNotificationCheckBox, 2, 0);
personalGrid->addWidget(&picDownloadCheckBox, 3, 0); personalGrid->addWidget(&picDownloadCheckBox, 3, 0, 1, 3);
personalGrid->addWidget(&picDownloadHqCheckBox, 4, 0); personalGrid->addWidget(&defaultUrlLabel, 4, 0, 1, 1);
personalGrid->addWidget(&highQualityURLLabel, 5, 0); personalGrid->addWidget(defaultUrlEdit, 4, 1, 1, 1);
personalGrid->addWidget(highQualityURLEdit, 5, 1); personalGrid->addWidget(&defaultUrlRestoreButton, 4, 2, 1, 1);
personalGrid->addWidget(&highQualityURLLinkLabel, 6, 1); personalGrid->addWidget(&fallbackUrlLabel, 5, 0, 1, 1);
personalGrid->addWidget(&clearDownloadedPicsButton, 6, 0); personalGrid->addWidget(fallbackUrlEdit, 5, 1, 1, 1);
personalGrid->addWidget(&fallbackUrlRestoreButton, 5, 2, 1, 1);
personalGrid->addWidget(&urlLinkLabel, 6, 1, 1, 1);
personalGrid->addWidget(&clearDownloadedPicsButton, 7, 0, 1, 3);
highQualityURLLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse); urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
highQualityURLLinkLabel.setOpenExternalLinks(true); urlLinkLabel.setOpenExternalLinks(true);
personalGroupBox = new QGroupBox; personalGroupBox = new QGroupBox;
personalGroupBox->setLayout(personalGrid); personalGroupBox->setLayout(personalGrid);
@ -154,6 +158,20 @@ QString GeneralSettingsPage::languageName(const QString &qmFile)
return translator.translate("GeneralSettingsPage", "English"); return translator.translate("GeneralSettingsPage", "English");
} }
void GeneralSettingsPage::defaultUrlRestoreButtonClicked()
{
QString path = PIC_URL_DEFAULT;
defaultUrlEdit->setText(path);
settingsCache->setPicUrl(path);
}
void GeneralSettingsPage::fallbackUrlRestoreButtonClicked()
{
QString path = PIC_URL_FALLBACK;
fallbackUrlEdit->setText(path);
settingsCache->setPicUrlFallback(path);
}
void GeneralSettingsPage::deckPathButtonClicked() void GeneralSettingsPage::deckPathButtonClicked()
{ {
QString path = QFileDialog::getExistingDirectory(this, tr("Choose path")); QString path = QFileDialog::getExistingDirectory(this, tr("Choose path"));
@ -238,7 +256,6 @@ void GeneralSettingsPage::retranslateUi()
personalGroupBox->setTitle(tr("Personal settings")); personalGroupBox->setTitle(tr("Personal settings"));
languageLabel.setText(tr("Language:")); languageLabel.setText(tr("Language:"));
picDownloadCheckBox.setText(tr("Download card pictures on the fly")); picDownloadCheckBox.setText(tr("Download card pictures on the fly"));
picDownloadHqCheckBox.setText(tr("Download card pictures from a custom URL"));
pathsGroupBox->setTitle(tr("Paths")); pathsGroupBox->setTitle(tr("Paths"));
deckPathLabel.setText(tr("Decks directory:")); deckPathLabel.setText(tr("Decks directory:"));
replaysPathLabel.setText(tr("Replays directory:")); replaysPathLabel.setText(tr("Replays directory:"));
@ -246,15 +263,21 @@ void GeneralSettingsPage::retranslateUi()
cardDatabasePathLabel.setText(tr("Card database:")); cardDatabasePathLabel.setText(tr("Card database:"));
tokenDatabasePathLabel.setText(tr("Token database:")); tokenDatabasePathLabel.setText(tr("Token database:"));
pixmapCacheLabel.setText(tr("Picture cache size:")); pixmapCacheLabel.setText(tr("Picture cache size:"));
highQualityURLLabel.setText(tr("Custom Card Download URL:")); defaultUrlLabel.setText(tr("Primary download URL:"));
highQualityURLLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(LINKING_FAQ_URL).arg(tr("Linking FAQ"))); fallbackUrlLabel.setText(tr("Fallback download URL:"));
urlLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(LINKING_FAQ_URL).arg(tr("Linking FAQ")));
clearDownloadedPicsButton.setText(tr("Reset/Clear Downloaded Pictures")); clearDownloadedPicsButton.setText(tr("Reset/Clear Downloaded Pictures"));
updateNotificationCheckBox.setText(tr("Notify when new client features are available")); updateNotificationCheckBox.setText(tr("Notify when new client features are available"));
defaultUrlRestoreButton.setText(tr("Reset"));
fallbackUrlRestoreButton.setText(tr("Reset"));
} }
void GeneralSettingsPage::setEnabledStatus(bool status) void GeneralSettingsPage::setEnabledStatus(bool status)
{ {
highQualityURLEdit->setEnabled(status); defaultUrlEdit->setEnabled(status);
fallbackUrlEdit->setEnabled(status);
defaultUrlRestoreButton.setEnabled(status);
fallbackUrlRestoreButton.setEnabled(status);
} }
AppearanceSettingsPage::AppearanceSettingsPage() AppearanceSettingsPage::AppearanceSettingsPage()

View file

@ -45,6 +45,8 @@ private slots:
void tokenDatabasePathButtonClicked(); void tokenDatabasePathButtonClicked();
void languageBoxChanged(int index); void languageBoxChanged(int index);
void setEnabledStatus(bool); void setEnabledStatus(bool);
void defaultUrlRestoreButtonClicked();
void fallbackUrlRestoreButtonClicked();
private: private:
QStringList findQmFiles(); QStringList findQmFiles();
QString languageName(const QString &qmFile); QString languageName(const QString &qmFile);
@ -53,13 +55,13 @@ private:
QLineEdit *picsPathEdit; QLineEdit *picsPathEdit;
QLineEdit *cardDatabasePathEdit; QLineEdit *cardDatabasePathEdit;
QLineEdit *tokenDatabasePathEdit; QLineEdit *tokenDatabasePathEdit;
QLineEdit *highQualityURLEdit; QLineEdit *defaultUrlEdit;
QLineEdit *fallbackUrlEdit;
QSpinBox pixmapCacheEdit; QSpinBox pixmapCacheEdit;
QGroupBox *personalGroupBox; QGroupBox *personalGroupBox;
QGroupBox *pathsGroupBox; QGroupBox *pathsGroupBox;
QComboBox languageBox; QComboBox languageBox;
QCheckBox picDownloadCheckBox; QCheckBox picDownloadCheckBox;
QCheckBox picDownloadHqCheckBox;
QCheckBox updateNotificationCheckBox; QCheckBox updateNotificationCheckBox;
QLabel languageLabel; QLabel languageLabel;
QLabel pixmapCacheLabel; QLabel pixmapCacheLabel;
@ -68,9 +70,12 @@ private:
QLabel picsPathLabel; QLabel picsPathLabel;
QLabel cardDatabasePathLabel; QLabel cardDatabasePathLabel;
QLabel tokenDatabasePathLabel; QLabel tokenDatabasePathLabel;
QLabel highQualityURLLabel; QLabel defaultUrlLabel;
QLabel highQualityURLLinkLabel; QLabel fallbackUrlLabel;
QLabel urlLinkLabel;
QPushButton clearDownloadedPicsButton; QPushButton clearDownloadedPicsButton;
QPushButton defaultUrlRestoreButton;
QPushButton fallbackUrlRestoreButton;
}; };
class AppearanceSettingsPage : public AbstractSettingsPage { class AppearanceSettingsPage : public AbstractSettingsPage {

View file

@ -0,0 +1,450 @@
#include "pictureloader.h"
#include "carddatabase.h"
#include "main.h"
#include "settingscache.h"
#include <QApplication>
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QImageReader>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QPainter>
#include <QPixmapCache>
#include <QSet>
#include <QSvgRenderer>
#include <QThread>
#include <QUrl>
class PictureToLoad::EnabledAndKeyCompareFunctor {
public:
inline bool operator()(CardSet *a, CardSet *b) const
{
if(a->getEnabled())
{
if(b->getEnabled())
{
// both enabled: sort by key
return a->getSortKey() < b->getSortKey();
} else {
// only a enabled
return true;
}
} else {
if(b->getEnabled())
{
// only b enabled
return false;
} else {
// both disabled: sort by key
return a->getSortKey() < b->getSortKey();
}
}
}
};
PictureToLoad::PictureToLoad(CardInfo *_card)
: card(_card), setIndex(0)
{
if (card) {
sortedSets = card->getSets();
qSort(sortedSets.begin(), sortedSets.end(), EnabledAndKeyCompareFunctor());
}
}
bool PictureToLoad::nextSet()
{
if (setIndex == sortedSets.size() - 1)
return false;
++setIndex;
return true;
}
QString PictureToLoad::getSetName() const
{
if (setIndex < sortedSets.size())
return sortedSets[setIndex]->getCorrectedShortName();
else
return QString("");
}
CardSet *PictureToLoad::getCurrentSet() const
{
if (setIndex < sortedSets.size())
return sortedSets[setIndex];
else
return 0;
}
QStringList PictureLoader::md5Blacklist = QStringList()
<< "db0c48db407a907c16ade38de048a441"; // card back returned by gatherer when card is not found
PictureLoader::PictureLoader()
: QObject(0),
downloadRunning(false), loadQueueRunning(false)
{
picsPath = settingsCache->getPicsPath();
picDownload = settingsCache->getPicDownload();
connect(this, SIGNAL(startLoadQueue()), this, SLOT(processLoadQueue()), Qt::QueuedConnection);
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
networkManager = new QNetworkAccessManager(this);
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(picDownloadFinished(QNetworkReply *)));
pictureLoaderThread = new QThread;
pictureLoaderThread->start(QThread::LowPriority);
moveToThread(pictureLoaderThread);
}
PictureLoader::~PictureLoader()
{
pictureLoaderThread->deleteLater();
}
void PictureLoader::processLoadQueue()
{
if (loadQueueRunning)
return;
loadQueueRunning = true;
forever {
mutex.lock();
if (loadQueue.isEmpty()) {
mutex.unlock();
loadQueueRunning = false;
return;
}
cardBeingLoaded = loadQueue.takeFirst();
mutex.unlock();
QString setName = cardBeingLoaded.getSetName();
QString correctedCardname = cardBeingLoaded.getCard()->getCorrectedName();
qDebug() << "Trying to load picture (set: " << setName << " card: " << correctedCardname << ")";
//The list of paths to the folders in which to search for images
QList<QString> picsPaths = QList<QString>() << picsPath + "/CUSTOM/" + correctedCardname;
if(!setName.isEmpty())
{
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
<< picsPath + "/downloadedPics/" + setName + "/" + correctedCardname;
}
QImage image;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
bool found = false;
//Iterates through the list of paths, searching for images with the desired name with any QImageReader-supported extension
for (int i = 0; i < picsPaths.length() && !found; i ++) {
imgReader.setFileName(picsPaths.at(i));
if (imgReader.read(&image)) {
qDebug() << "Picture found on disk (set: " << setName << " card: " << correctedCardname << ")";
imageLoaded(cardBeingLoaded.getCard(), image);
found = true;
break;
}
imgReader.setFileName(picsPaths.at(i) + ".full");
if (imgReader.read(&image)) {
qDebug() << "Picture.full found on disk (set: " << setName << " card: " << correctedCardname << ")";
imageLoaded(cardBeingLoaded.getCard(), image);
found = true;
}
}
if (!found) {
if (picDownload) {
qDebug() << "Picture NOT found, trying to download (set: " << setName << " card: " << correctedCardname << ")";
cardsToDownload.append(cardBeingLoaded);
cardBeingLoaded=0;
if (!downloadRunning)
startNextPicDownload();
} else {
if (cardBeingLoaded.nextSet())
{
qDebug() << "Picture NOT found and download disabled, moving to next set (newset: " << setName << " card: " << correctedCardname << ")";
mutex.lock();
loadQueue.prepend(cardBeingLoaded);
cardBeingLoaded=0;
mutex.unlock();
} else {
qDebug() << "Picture NOT found, download disabled, no more sets to try: BAILING OUT (oldset: " << setName << " card: " << correctedCardname << ")";
imageLoaded(cardBeingLoaded.getCard(), QImage());
}
}
}
}
}
QString PictureLoader::getPicUrl()
{
if (!picDownload) return QString("");
CardInfo *card = cardBeingDownloaded.getCard();
CardSet *set=cardBeingDownloaded.getCurrentSet();
QString picUrl = QString("");
// if sets have been defined for the card, they can contain custom picUrls
if(set)
{
picUrl = card->getCustomPicURL(set->getShortName());
if (!picUrl.isEmpty())
return picUrl;
}
// if a card has a muid, use the default url; if not, use the fallback
int muid = set ? card->getMuId(set->getShortName()) : 0;
picUrl = muid ? settingsCache->getPicUrl() : settingsCache->getPicUrlFallback();
picUrl.replace("!name!", QUrl::toPercentEncoding(card->getCorrectedName()));
picUrl.replace("!name_lower!", QUrl::toPercentEncoding(card->getCorrectedName().toLower()));
picUrl.replace("!cardid!", QUrl::toPercentEncoding(QString::number(muid)));
if (set)
{
picUrl.replace("!setcode!", QUrl::toPercentEncoding(set->getShortName()));
picUrl.replace("!setcode_lower!", QUrl::toPercentEncoding(set->getShortName().toLower()));
picUrl.replace("!setname!", QUrl::toPercentEncoding(set->getLongName()));
picUrl.replace("!setname_lower!", QUrl::toPercentEncoding(set->getLongName().toLower()));
}
if (
picUrl.contains("!name!") ||
picUrl.contains("!name_lower!") ||
picUrl.contains("!setcode!") ||
picUrl.contains("!setcode_lower!") ||
picUrl.contains("!setname!") ||
picUrl.contains("!setname_lower!") ||
picUrl.contains("!cardid!")
)
{
qDebug() << "Insufficient card data to download" << card->getName() << "Url:" << picUrl;
return QString("");
}
return picUrl;
}
void PictureLoader::startNextPicDownload()
{
if (cardsToDownload.isEmpty()) {
cardBeingDownloaded = 0;
downloadRunning = false;
return;
}
downloadRunning = true;
cardBeingDownloaded = cardsToDownload.takeFirst();
QString picUrl = getPicUrl();
if (picUrl.isEmpty()) {
downloadRunning = false;
picDownloadFailed();
} else {
QUrl url(picUrl);
QNetworkRequest req(url);
qDebug() << "starting picture download:" << cardBeingDownloaded.getCard()->getName() << "Url:" << req.url();
networkManager->get(req);
}
}
void PictureLoader::picDownloadFailed()
{
if (cardBeingDownloaded.nextSet())
{
qDebug() << "Picture NOT found, download failed, moving to next set (newset: " << cardBeingDownloaded.getSetName() << " card: " << cardBeingDownloaded.getCard()->getCorrectedName() << ")";
mutex.lock();
loadQueue.prepend(cardBeingDownloaded);
mutex.unlock();
emit startLoadQueue();
} else {
qDebug() << "Picture NOT found, download failed, no more sets to try: BAILING OUT (oldset: " << cardBeingDownloaded.getSetName() << " card: " << cardBeingDownloaded.getCard()->getCorrectedName() << ")";
cardBeingDownloaded = 0;
imageLoaded(cardBeingDownloaded.getCard(), QImage());
}
}
void PictureLoader::picDownloadFinished(QNetworkReply *reply)
{
if (reply->error()) {
qDebug() << "Download failed:" << reply->errorString();
}
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode == 301 || statusCode == 302) {
QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
QNetworkRequest req(redirectUrl);
qDebug() << "following redirect:" << cardBeingDownloaded.getCard()->getName() << "Url:" << req.url();
networkManager->get(req);
return;
}
const QByteArray &picData = reply->peek(reply->size()); //peek is used to keep the data in the buffer for use by QImageReader
// check if the image is blacklisted
QString md5sum = QCryptographicHash::hash(picData, QCryptographicHash::Md5).toHex();
if(md5Blacklist.contains(md5sum))
{
qDebug() << "Picture downloaded, but blacklisted (" << md5sum << "), will consider it as not found";
picDownloadFailed();
reply->deleteLater();
startNextPicDownload();
return;
}
QImage testImage;
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setDevice(reply);
QString extension = "." + imgReader.format(); //the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the QImageReader buffer
if (extension == ".jpeg")
extension = ".jpg";
if (imgReader.read(&testImage)) {
QString setName = cardBeingDownloaded.getSetName();
if(!setName.isEmpty())
{
if (!QDir().mkpath(picsPath + "/downloadedPics/" + setName)) {
qDebug() << picsPath + "/downloadedPics/" + setName + " could not be created.";
return;
}
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" + cardBeingDownloaded.getCard()->getCorrectedName() + extension);
if (!newPic.open(QIODevice::WriteOnly))
return;
newPic.write(picData);
newPic.close();
}
imageLoaded(cardBeingDownloaded.getCard(), testImage);
} else {
picDownloadFailed();
}
reply->deleteLater();
startNextPicDownload();
}
void PictureLoader::enqueueImageLoad(CardInfo *card)
{
QMutexLocker locker(&mutex);
// avoid queueing the same card more than once
if(card == 0 || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard())
return;
foreach(PictureToLoad pic, loadQueue)
{
if(pic.getCard() == card)
return;
}
loadQueue.append(PictureToLoad(card));
emit startLoadQueue();
}
void PictureLoader::picDownloadChanged()
{
QMutexLocker locker(&mutex);
picDownload = settingsCache->getPicDownload();
QPixmapCache::clear();
}
void PictureLoader::picsPathChanged()
{
QMutexLocker locker(&mutex);
picsPath = settingsCache->getPicsPath();
QPixmapCache::clear();
}
void PictureLoader::getPixmap(QPixmap &pixmap, CardInfo *card, QSize size)
{
QPixmap bigPixmap;
if(card)
{
// search for an exact size copy of the picure in cache
QString key = card->getPixmapCacheKey();
QString sizekey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
if(QPixmapCache::find(sizekey, &pixmap))
return;
// load the image and create a copy of the correct size
if(QPixmapCache::find(key, &bigPixmap))
{
pixmap = bigPixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(sizekey, pixmap);
return;
}
}
// load a temporary back picture
QString backCacheKey = "_trice_card_back_" + QString::number(size.width()) + QString::number(size.height());
if(!QPixmapCache::find(backCacheKey, &pixmap))
{
pixmap = QPixmap("theme:cardback").scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(backCacheKey, pixmap);
}
if(card)
{
// add the card to the load queue
getInstance().enqueueImageLoad(card);
}
}
void PictureLoader::imageLoaded(CardInfo *card, const QImage &image)
{
if(image.isNull())
return;
if(card->getUpsideDownArt())
{
QImage mirrorImage = image.mirrored(true, true);
QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(mirrorImage));
} else {
QPixmapCache::insert(card->getPixmapCacheKey(), QPixmap::fromImage(image));
}
emit card->pixmapUpdated();
}
void PictureLoader::clearPixmapCache(CardInfo *card)
{
//qDebug() << "Deleting pixmap for" << name;
if(card)
QPixmapCache::remove(card->getPixmapCacheKey());
}
void PictureLoader::clearPixmapCache()
{
QPixmapCache::clear();
}
void PictureLoader::cacheCardPixmaps(QList<CardInfo *> cards)
{
QPixmap tmp;
// never cache more than 300 cards at once for a single deck
int max = qMin(cards.size(), 300);
for (int i = 0; i < max; ++i)
{
CardInfo * card = cards.at(i);
if(!card)
continue;
QString key = card->getPixmapCacheKey();
if(QPixmapCache::find(key, &tmp))
continue;
getInstance().enqueueImageLoad(card);
}
}

View file

@ -0,0 +1,78 @@
#ifndef PICTURELOADER_H
#define PICTURELOADER_H
#include <QMap>
#include <QList>
#include <QNetworkRequest>
#include <QMutex>
class CardInfo;
class CardSet;
class QNetworkAccessManager;
class QNetworkReply;
class QThread;
class PictureToLoad {
private:
class EnabledAndKeyCompareFunctor;
CardInfo *card;
QList<CardSet *> sortedSets;
int setIndex;
bool hq;
public:
PictureToLoad(CardInfo *_card = 0);
CardInfo *getCard() const { return card; }
CardSet *getCurrentSet() const;
QString getSetName() const;
bool nextSet();
};
class PictureLoader : public QObject {
Q_OBJECT
public:
static PictureLoader& getInstance()
{
static PictureLoader instance;
return instance;
}
private:
PictureLoader();
~PictureLoader();
// Don't implement
PictureLoader(PictureLoader const&);
void operator=(PictureLoader const&);
static QStringList md5Blacklist;
QThread *pictureLoaderThread;
QString picsPath;
QList<PictureToLoad> loadQueue;
QMutex mutex;
QNetworkAccessManager *networkManager;
QList<PictureToLoad> cardsToDownload;
PictureToLoad cardBeingLoaded;
PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning;
void startNextPicDownload();
void imageLoaded(CardInfo *card, const QImage &image);
QString getPicUrl();
public:
void enqueueImageLoad(CardInfo *card);
static void getPixmap(QPixmap &pixmap, CardInfo *card, QSize size);
static void clearPixmapCache(CardInfo *card);
static void clearPixmapCache();
static void cacheCardPixmaps(QList<CardInfo *> cards);
private slots:
void picDownloadFinished(QNetworkReply *reply);
void picDownloadFailed();
void picDownloadChanged();
void picsPathChanged();
public slots:
void processLoadQueue();
signals:
void startLoadQueue();
};
#endif

View file

@ -165,12 +165,9 @@ SettingsCache::SettingsCache()
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT; pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
picDownload = settings->value("personal/picturedownload", true).toBool(); picDownload = settings->value("personal/picturedownload", true).toBool();
picDownloadHq = settings->value("personal/picturedownloadhq", true).toBool();
picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString(); picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString();
picUrlHq = settings->value("personal/picUrlHq", PIC_URL_HQ_DEFAULT).toString();
picUrlFallback = settings->value("personal/picUrlFallback", PIC_URL_FALLBACK).toString(); picUrlFallback = settings->value("personal/picUrlFallback", PIC_URL_FALLBACK).toString();
picUrlHqFallback = settings->value("personal/picUrlHqFallback", PIC_URL_HQ_FALLBACK).toString();
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray(); mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool(); notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
@ -325,37 +322,18 @@ void SettingsCache::setPicDownload(int _picDownload)
emit picDownloadChanged(); emit picDownloadChanged();
} }
void SettingsCache::setPicDownloadHq(int _picDownloadHq)
{
picDownloadHq = _picDownloadHq;
settings->setValue("personal/picturedownloadhq", picDownloadHq);
emit picDownloadHqChanged();
}
void SettingsCache::setPicUrl(const QString &_picUrl) void SettingsCache::setPicUrl(const QString &_picUrl)
{ {
picUrl = _picUrl; picUrl = _picUrl;
settings->setValue("personal/picUrl", picUrl); settings->setValue("personal/picUrl", picUrl);
} }
void SettingsCache::setPicUrlHq(const QString &_picUrlHq)
{
picUrlHq = _picUrlHq;
settings->setValue("personal/picUrlHq", picUrlHq);
}
void SettingsCache::setPicUrlFallback(const QString &_picUrlFallback) void SettingsCache::setPicUrlFallback(const QString &_picUrlFallback)
{ {
picUrlFallback = _picUrlFallback; picUrlFallback = _picUrlFallback;
settings->setValue("personal/picUrlFallback", picUrlFallback); settings->setValue("personal/picUrlFallback", picUrlFallback);
} }
void SettingsCache::setPicUrlHqFallback(const QString &_picUrlHqFallback)
{
picUrlHqFallback = _picUrlHqFallback;
settings->setValue("personal/picUrlHqFallback", picUrlHqFallback);
}
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled) void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
{ {
notificationsEnabled = _notificationsEnabled; notificationsEnabled = _notificationsEnabled;

View file

@ -14,8 +14,6 @@
// the falbacks are used for cards without a muid // the falbacks are used for cards without a muid
#define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card" #define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
#define PIC_URL_FALLBACK "http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card" #define PIC_URL_FALLBACK "http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"
#define PIC_URL_HQ_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
#define PIC_URL_HQ_FALLBACK "http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"
// size should be a multiple of 64 // size should be a multiple of 64
#define PIXMAPCACHE_SIZE_DEFAULT 2047 #define PIXMAPCACHE_SIZE_DEFAULT 2047
#define PIXMAPCACHE_SIZE_MIN 64 #define PIXMAPCACHE_SIZE_MIN 64
@ -32,7 +30,6 @@ signals:
void tokenDatabasePathChanged(); void tokenDatabasePathChanged();
void themeChanged(); void themeChanged();
void picDownloadChanged(); void picDownloadChanged();
void picDownloadHqChanged();
void displayCardNamesChanged(); void displayCardNamesChanged();
void horizontalHandChanged(); void horizontalHandChanged();
void handJustificationChanged(); void handJustificationChanged();
@ -60,7 +57,6 @@ private:
QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath, themeName; QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath, themeName;
bool notifyAboutUpdates; bool notifyAboutUpdates;
bool picDownload; bool picDownload;
bool picDownloadHq;
bool notificationsEnabled; bool notificationsEnabled;
bool spectatorNotificationsEnabled; bool spectatorNotificationsEnabled;
bool doubleClickToPlay; bool doubleClickToPlay;
@ -87,9 +83,7 @@ private:
bool ignoreUnregisteredUsers; bool ignoreUnregisteredUsers;
bool ignoreUnregisteredUserMessages; bool ignoreUnregisteredUserMessages;
QString picUrl; QString picUrl;
QString picUrlHq;
QString picUrlFallback; QString picUrlFallback;
QString picUrlHqFallback;
QString clientID; QString clientID;
int pixmapCacheSize; int pixmapCacheSize;
bool scaleCards; bool scaleCards;
@ -127,7 +121,6 @@ public:
QString getChatMentionColor() const { return chatMentionColor; } QString getChatMentionColor() const { return chatMentionColor; }
QString getChatHighlightColor() const { return chatHighlightColor; } QString getChatHighlightColor() const { return chatHighlightColor; }
bool getPicDownload() const { return picDownload; } bool getPicDownload() const { return picDownload; }
bool getPicDownloadHq() const { return picDownloadHq; }
bool getNotificationsEnabled() const { return notificationsEnabled; } bool getNotificationsEnabled() const { return notificationsEnabled; }
bool getSpectatorNotificationsEnabled() const { return spectatorNotificationsEnabled; } bool getSpectatorNotificationsEnabled() const { return spectatorNotificationsEnabled; }
bool getNotifyAboutUpdates() const { return notifyAboutUpdates; } bool getNotifyAboutUpdates() const { return notifyAboutUpdates; }
@ -160,9 +153,7 @@ public:
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; } bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
bool getIgnoreUnregisteredUserMessages() const { return ignoreUnregisteredUserMessages; } bool getIgnoreUnregisteredUserMessages() const { return ignoreUnregisteredUserMessages; }
QString getPicUrl() const { return picUrl; } QString getPicUrl() const { return picUrl; }
QString getPicUrlHq() const { return picUrlHq; }
QString getPicUrlFallback() const { return picUrlFallback; } QString getPicUrlFallback() const { return picUrlFallback; }
QString getPicUrlHqFallback() const { return picUrlHqFallback; }
int getPixmapCacheSize() const { return pixmapCacheSize; } int getPixmapCacheSize() const { return pixmapCacheSize; }
bool getScaleCards() const { return scaleCards; } bool getScaleCards() const { return scaleCards; }
bool getShowMessagePopup() const { return showMessagePopups; } bool getShowMessagePopup() const { return showMessagePopups; }
@ -204,7 +195,6 @@ public slots:
void setChatMentionColor(const QString &_chatMentionColor); void setChatMentionColor(const QString &_chatMentionColor);
void setChatHighlightColor(const QString &_chatHighlightColor); void setChatHighlightColor(const QString &_chatHighlightColor);
void setPicDownload(int _picDownload); void setPicDownload(int _picDownload);
void setPicDownloadHq(int _picDownloadHq);
void setNotificationsEnabled(int _notificationsEnabled); void setNotificationsEnabled(int _notificationsEnabled);
void setSpectatorNotificationsEnabled(int _spectatorNotificationsEnabled); void setSpectatorNotificationsEnabled(int _spectatorNotificationsEnabled);
void setDoubleClickToPlay(int _doubleClickToPlay); void setDoubleClickToPlay(int _doubleClickToPlay);
@ -231,9 +221,7 @@ public slots:
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers); void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages); void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
void setPicUrl(const QString &_picUrl); void setPicUrl(const QString &_picUrl);
void setPicUrlHq(const QString &_picUrlHq);
void setPicUrlFallback(const QString &_picUrlFallback); void setPicUrlFallback(const QString &_picUrlFallback);
void setPicUrlHqFallback(const QString &_picUrlHqFallback);
void setPixmapCacheSize(const int _pixmapCacheSize); void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardScaling(const int _scaleCards); void setCardScaling(const int _scaleCards);
void setShowMessagePopups(const int _showMessagePopups); void setShowMessagePopups(const int _showMessagePopups);

View file

@ -26,6 +26,7 @@
#include "tab_deck_editor.h" #include "tab_deck_editor.h"
#include "window_sets.h" #include "window_sets.h"
#include "carddatabase.h" #include "carddatabase.h"
#include "pictureloader.h"
#include "carddatabasemodel.h" #include "carddatabasemodel.h"
#include "decklistmodel.h" #include "decklistmodel.h"
#include "cardinfowidget.h" #include "cardinfowidget.h"
@ -1058,7 +1059,7 @@ void TabDeckEditor::setDeck(DeckLoader *_deck)
deckView->expandAll(); deckView->expandAll();
setModified(false); setModified(false);
db->cacheCardPixmaps(deckModel->getDeckList()->getCardList()); PictureLoader::cacheCardPixmaps(db->getCards(deckModel->getDeckList()->getCardList()));
deckView->expandAll(); deckView->expandAll();
setModified(false); setModified(false);
} }

View file

@ -32,6 +32,7 @@
#include "main.h" #include "main.h"
#include "settingscache.h" #include "settingscache.h"
#include "carddatabase.h" #include "carddatabase.h"
#include "pictureloader.h"
#include "replay_timeline_widget.h" #include "replay_timeline_widget.h"
#include "lineeditcompleter.h" #include "lineeditcompleter.h"
@ -242,7 +243,7 @@ void DeckViewContainer::deckSelectFinished(const Response &r)
{ {
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext); const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
DeckLoader newDeck(QString::fromStdString(resp.deck())); DeckLoader newDeck(QString::fromStdString(resp.deck()));
db->cacheCardPixmaps(newDeck.getCardList()); PictureLoader::cacheCardPixmaps(db->getCards(newDeck.getCardList()));
setDeck(newDeck); setDeck(newDeck);
} }
@ -1044,7 +1045,7 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event, int /*e
DeckViewContainer *deckViewContainer = deckViewContainers.value(playerId); DeckViewContainer *deckViewContainer = deckViewContainers.value(playerId);
if (playerInfo.has_deck_list()) { if (playerInfo.has_deck_list()) {
DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list())); DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list()));
db->cacheCardPixmaps(newDeck.getCardList()); PictureLoader::cacheCardPixmaps(db->getCards(newDeck.getCardList()));
deckViewContainer->setDeck(newDeck); deckViewContainer->setDeck(newDeck);
player->setDeck(newDeck); player->setDeck(newDeck);
} }

View file

@ -1,6 +1,8 @@
#include "window_sets.h" #include "window_sets.h"
#include "setsmodel.h" #include "setsmodel.h"
#include "pictureloader.h"
#include "main.h" #include "main.h"
#include <QTreeView> #include <QTreeView>
#include <QGridLayout> #include <QGridLayout>
#include <QHeaderView> #include <QHeaderView>
@ -123,7 +125,7 @@ WndSets::~WndSets()
void WndSets::actSave() void WndSets::actSave()
{ {
model->save(db); model->save(db);
db->clearPixmapCache(); PictureLoader::clearPixmapCache();
QMessageBox::information(this, tr("Success"), tr("The sets database has been saved successfully.")); QMessageBox::information(this, tr("Success"), tr("The sets database has been saved successfully."));
close(); close();
} }

View file

@ -29,7 +29,6 @@
<xs:extension base="xs:string"> <xs:extension base="xs:string">
<xs:attribute type="xs:int" name="muId" use="optional"/> <xs:attribute type="xs:int" name="muId" use="optional"/>
<xs:attribute type="xs:anyURI" name="picUrl" use="optional"/> <xs:attribute type="xs:anyURI" name="picUrl" use="optional"/>
<xs:attribute type="xs:anyURI" name="picUrlHq" use="optional"/>
</xs:extension> </xs:extension>
</xs:simpleContent> </xs:simpleContent>
</xs:complexType> </xs:complexType>

View file

@ -12,6 +12,7 @@ SET(oracle_SOURCES
src/oraclewizard.cpp src/oraclewizard.cpp
src/oracleimporter.cpp src/oracleimporter.cpp
../cockatrice/src/carddatabase.cpp ../cockatrice/src/carddatabase.cpp
../cockatrice/src/pictureloader.cpp
../cockatrice/src/settingscache.cpp ../cockatrice/src/settingscache.cpp
../cockatrice/src/shortcutssettings.cpp ../cockatrice/src/shortcutssettings.cpp
../cockatrice/src/settings/carddatabasesettings.cpp ../cockatrice/src/settings/carddatabasesettings.cpp

View file

@ -2,6 +2,7 @@
#define ORACLEIMPORTER_H #define ORACLEIMPORTER_H
#include <QMap> #include <QMap>
#include <QVariant>
#include <carddatabase.h> #include <carddatabase.h>