Reimplemented PictureLoader as a singleton
* Removed remaining picture handling from card database and cardinfo * removed the “noCard object” hack
This commit is contained in:
parent
8125358052
commit
f6c7f3355f
20 changed files with 654 additions and 704 deletions
|
@ -95,6 +95,7 @@ SET(cockatrice_SOURCES
|
|||
src/qt-json/json.cpp
|
||||
src/soundengine.cpp
|
||||
src/pending_command.cpp
|
||||
src/pictureloader.cpp
|
||||
src/shortcutssettings.cpp
|
||||
src/sequenceEdit/sequenceedit.cpp
|
||||
src/sequenceEdit/shortcutstab.cpp
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "carddatabase.h"
|
||||
#include "cardinfowidget.h"
|
||||
#include "abstractcarditem.h"
|
||||
#include "pictureloader.h"
|
||||
#include "settingscache.h"
|
||||
#include "main.h"
|
||||
#include "gamescene.h"
|
||||
|
@ -45,6 +46,7 @@ void AbstractCardItem::pixmapUpdated()
|
|||
void AbstractCardItem::cardInfoUpdated()
|
||||
{
|
||||
info = db->getCard(name);
|
||||
if(info)
|
||||
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
|
||||
}
|
||||
|
||||
|
@ -93,7 +95,7 @@ void AbstractCardItem::paintPicture(QPainter *painter, const QSizeF &translatedS
|
|||
QPixmap translatedPixmap;
|
||||
// don't even spend time trying to load the picture if our size is too small
|
||||
if(translatedSize.width() > 10)
|
||||
imageSource->getPixmap(translatedSize.toSize(), translatedPixmap);
|
||||
PictureLoader::getPixmap(translatedPixmap, imageSource, translatedSize.toSize());
|
||||
|
||||
painter->save();
|
||||
QColor bgColor = Qt::transparent;
|
||||
|
@ -191,9 +193,11 @@ void AbstractCardItem::setName(const QString &_name)
|
|||
return;
|
||||
|
||||
emit deleteCardInfoPopup(name);
|
||||
if(info)
|
||||
disconnect(info, 0, this, 0);
|
||||
name = _name;
|
||||
info = db->getCard(name);
|
||||
if(info)
|
||||
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(pixmapUpdated()));
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
#include "carddatabase.h"
|
||||
#include "pictureloader.h"
|
||||
#include "settingscache.h"
|
||||
#include "thememanager.h"
|
||||
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QPainter>
|
||||
#include <QUrl>
|
||||
#include <QSet>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QDebug>
|
||||
#include <QImageReader>
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
|
||||
const int CardDatabase::versionNeeded = 3;
|
||||
|
@ -88,38 +84,6 @@ void SetList::sortByKey()
|
|||
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 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,
|
||||
const QString &_name,
|
||||
bool _isToken,
|
||||
|
@ -539,7 +175,6 @@ CardInfo::CardInfo(CardDatabase *_db,
|
|||
int _tableRow,
|
||||
const SetList &_sets,
|
||||
const QStringMap &_customPicURLs,
|
||||
const QStringMap &_customPicURLsHq,
|
||||
MuidMap _muIds
|
||||
)
|
||||
: db(_db),
|
||||
|
@ -556,7 +191,6 @@ CardInfo::CardInfo(CardDatabase *_db,
|
|||
upsideDownArt(_upsideDownArt),
|
||||
loyalty(_loyalty),
|
||||
customPicURLs(_customPicURLs),
|
||||
customPicURLsHq(_customPicURLsHq),
|
||||
muIds(_muIds),
|
||||
cipt(_cipt),
|
||||
tableRow(_tableRow)
|
||||
|
@ -570,7 +204,7 @@ CardInfo::CardInfo(CardDatabase *_db,
|
|||
|
||||
CardInfo::~CardInfo()
|
||||
{
|
||||
clearPixmapCache();
|
||||
PictureLoader::clearPixmapCache(this);
|
||||
}
|
||||
|
||||
QString CardInfo::getMainCardType() const
|
||||
|
@ -617,82 +251,6 @@ void CardInfo::addToSet(CardSet *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 simpleName(name);
|
||||
|
||||
|
@ -731,10 +289,6 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
|
|||
if(!tmpString.isEmpty())
|
||||
xml.writeAttribute("picURL", tmpString);
|
||||
|
||||
tmpString = info->getCustomPicURLHq(tmpSet);
|
||||
if(!tmpString.isEmpty())
|
||||
xml.writeAttribute("picURLHq", tmpString);
|
||||
|
||||
xml.writeCharacters(tmpSet);
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
@ -767,37 +321,18 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info)
|
|||
}
|
||||
|
||||
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(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
|
||||
connect(settingsCache, SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
|
||||
connect(settingsCache, SIGNAL(picDownloadHqChanged()), this, SLOT(picDownloadHqChanged()));
|
||||
|
||||
loadCardDatabase();
|
||||
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()
|
||||
{
|
||||
clear();
|
||||
delete noCard;
|
||||
|
||||
pictureLoader->deleteLater();
|
||||
pictureLoaderThread->wait();
|
||||
delete pictureLoaderThread;
|
||||
}
|
||||
|
||||
void CardDatabase::clear()
|
||||
|
@ -839,6 +374,15 @@ CardInfo *CardDatabase::getCard(const QString &cardName, bool 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) {
|
||||
QString simpleName = CardInfo::simplifyName(cardName);
|
||||
return getCardFromMap(simpleNameCards, simpleName, createIfNotFound);
|
||||
|
@ -866,21 +410,6 @@ SetList CardDatabase::getSetList() const
|
|||
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)
|
||||
{
|
||||
while (!xml.atEnd()) {
|
||||
|
@ -918,7 +447,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
|
|||
if (xml.name() == "card") {
|
||||
QString name, manacost, cmc, type, pt, text;
|
||||
QStringList colors, relatedCards;
|
||||
QStringMap customPicURLs, customPicURLsHq;
|
||||
QStringMap customPicURLs;
|
||||
MuidMap muids;
|
||||
SetList sets;
|
||||
int tableRow = 0;
|
||||
|
@ -951,9 +480,6 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
|
|||
if (attrs.hasAttribute("picURL")) {
|
||||
customPicURLs[setName] = attrs.value("picURL").toString();
|
||||
}
|
||||
if (attrs.hasAttribute("picURLHq")) {
|
||||
customPicURLsHq[setName] = attrs.value("picURLHq").toString();
|
||||
}
|
||||
} else if (xml.name() == "color")
|
||||
colors << xml.readElementText();
|
||||
else if (xml.name() == "related")
|
||||
|
@ -971,23 +497,23 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool 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) {
|
||||
if (cardName.isEmpty())
|
||||
return noCard;
|
||||
else if (cardMap.contains(cardName))
|
||||
if (cardMap.contains(cardName))
|
||||
return cardMap.value(cardName);
|
||||
else if (createIfNotFound) {
|
||||
|
||||
if (createIfNotFound) {
|
||||
CardInfo *newCard = new CardInfo(this, cardName, true);
|
||||
newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME));
|
||||
cardMap.insert(cardName, newCard);
|
||||
return newCard;
|
||||
} else
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1061,26 +587,6 @@ bool CardDatabase::saveToFile(const QString &fileName, bool tokens)
|
|||
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()
|
||||
{
|
||||
emit cardListChanged();
|
||||
|
@ -1159,31 +665,6 @@ QStringList CardDatabase::getAllMainCardTypes() const
|
|||
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()
|
||||
{
|
||||
SetList sets = getSetList();
|
||||
|
|
|
@ -8,17 +8,9 @@
|
|||
#include <QDataStream>
|
||||
#include <QList>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QNetworkRequest>
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
#include <QPixmapCache>
|
||||
|
||||
class CardDatabase;
|
||||
class CardInfo;
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class QNetworkRequest;
|
||||
|
||||
typedef QMap<QString, QString> QStringMap;
|
||||
|
||||
|
@ -55,9 +47,7 @@ public:
|
|||
class SetList : public QList<CardSet *> {
|
||||
private:
|
||||
class KeyCompareFunctor;
|
||||
class EnabledAndKeyCompareFunctor;
|
||||
public:
|
||||
void sortByEnabledAndKey();
|
||||
void sortByKey();
|
||||
void guessSortKeys();
|
||||
void enableAllUnknown();
|
||||
|
@ -67,53 +57,6 @@ public:
|
|||
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 {
|
||||
Q_OBJECT
|
||||
private:
|
||||
|
@ -138,7 +81,7 @@ private:
|
|||
QStringList relatedCards;
|
||||
bool upsideDownArt;
|
||||
int loyalty;
|
||||
QStringMap customPicURLs, customPicURLsHq;
|
||||
QStringMap customPicURLs;
|
||||
MuidMap muIds;
|
||||
bool cipt;
|
||||
int tableRow;
|
||||
|
@ -160,7 +103,6 @@ public:
|
|||
int _tableRow = 0,
|
||||
const SetList &_sets = SetList(),
|
||||
const QStringMap &_customPicURLs = QStringMap(),
|
||||
const QStringMap &_customPicURLsHq = QStringMap(),
|
||||
MuidMap muids = MuidMap()
|
||||
);
|
||||
~CardInfo();
|
||||
|
@ -173,6 +115,7 @@ public:
|
|||
const QString &getCardType() const { return cardtype; }
|
||||
const QString &getPowTough() const { return powtough; }
|
||||
const QString &getText() const { return text; }
|
||||
const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
|
||||
const int &getLoyalty() const { return loyalty; }
|
||||
bool getCipt() const { return cipt; }
|
||||
void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); }
|
||||
|
@ -185,7 +128,6 @@ public:
|
|||
const QStringList &getRelatedCards() const { return relatedCards; }
|
||||
bool getUpsideDownArt() const { return upsideDownArt; }
|
||||
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); }
|
||||
QString getMainCardType() const;
|
||||
QString getCorrectedName() const;
|
||||
|
@ -193,22 +135,14 @@ public:
|
|||
void setTableRow(int _tableRow) { tableRow = _tableRow; }
|
||||
void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(this); }
|
||||
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 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
|
||||
* less strict name-matching.
|
||||
*/
|
||||
static QString simplifyName(const QString &name);
|
||||
public slots:
|
||||
void updatePixmapCache();
|
||||
signals:
|
||||
void pixmapUpdated();
|
||||
void cardInfoChanged(CardInfo *card);
|
||||
|
@ -237,10 +171,6 @@ protected:
|
|||
*/
|
||||
SetNameMap sets;
|
||||
|
||||
CardInfo *noCard;
|
||||
|
||||
QThread *pictureLoaderThread;
|
||||
PictureLoader *pictureLoader;
|
||||
LoadStatus loadStatus;
|
||||
bool detectedFirstRun;
|
||||
private:
|
||||
|
@ -258,13 +188,14 @@ public:
|
|||
void clear();
|
||||
void addCard(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
|
||||
* 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);
|
||||
QList<CardInfo *> getCardList() const { return cards.values(); }
|
||||
|
@ -275,20 +206,12 @@ public:
|
|||
QStringList getAllMainCardTypes() const;
|
||||
LoadStatus getLoadStatus() const { return loadStatus; }
|
||||
bool getLoadSuccess() const { return loadStatus == Ok; }
|
||||
void cacheCardPixmaps(const QStringList &cardNames);
|
||||
void loadImage(CardInfo *card);
|
||||
bool hasDetectedFirstRun();
|
||||
public slots:
|
||||
void clearPixmapCache();
|
||||
LoadStatus loadCardDatabase(const QString &path, bool tokens = false);
|
||||
void loadCustomCardDatabases(const QString &path);
|
||||
void emitCardListChanged();
|
||||
private slots:
|
||||
void imageLoaded(CardInfo *card, QImage image);
|
||||
void picDownloadChanged();
|
||||
void picDownloadHqChanged();
|
||||
void picsPathChanged();
|
||||
|
||||
void loadCardDatabase();
|
||||
void loadTokenDatabase();
|
||||
signals:
|
||||
|
|
|
@ -93,6 +93,7 @@ void CardFrame::setCard(CardInfo *card)
|
|||
if (info)
|
||||
disconnect(info, 0, this, 0);
|
||||
info = card;
|
||||
if(info)
|
||||
connect(info, SIGNAL(destroyed()), this, SLOT(clear()));
|
||||
text->setCard(info);
|
||||
pic->setCard(info);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "carditem.h"
|
||||
#include "carddatabase.h"
|
||||
#include "pictureloader.h"
|
||||
#include "main.h"
|
||||
|
||||
CardInfoPicture::CardInfoPicture(QWidget *parent)
|
||||
|
@ -21,6 +22,7 @@ void CardInfoPicture::setCard(CardInfo *card)
|
|||
if (info)
|
||||
disconnect(info, 0, this, 0);
|
||||
info = card;
|
||||
if(info)
|
||||
connect(info, SIGNAL(pixmapUpdated()), this, SLOT(updatePixmap()));
|
||||
|
||||
updatePixmap();
|
||||
|
@ -40,13 +42,13 @@ void CardInfoPicture::updatePixmap()
|
|||
void CardInfoPicture::loadPixmap()
|
||||
{
|
||||
if(info)
|
||||
info->getPixmap(size(), resizedPixmap);
|
||||
PictureLoader::getPixmap(resizedPixmap, info, size());
|
||||
else
|
||||
resizedPixmap = QPixmap();
|
||||
|
||||
|
||||
if (resizedPixmap.isNull())
|
||||
db->getCard()->getPixmap(size(), resizedPixmap);
|
||||
PictureLoader::getPixmap(resizedPixmap, db->getCard(), size());
|
||||
}
|
||||
|
||||
void CardInfoPicture::paintEvent(QPaintEvent *)
|
||||
|
|
|
@ -53,6 +53,7 @@ CardInfoText::CardInfoText(QWidget *parent)
|
|||
|
||||
void CardInfoText::setCard(CardInfo *card)
|
||||
{
|
||||
if(card) {
|
||||
nameLabel2->setText(card->getName());
|
||||
manacostLabel2->setText(card->getManaCost());
|
||||
colorLabel2->setText(card->getColors().join(""));
|
||||
|
@ -60,6 +61,15 @@ void CardInfoText::setCard(CardInfo *card)
|
|||
powtoughLabel2->setText(card->getPowTough());
|
||||
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()
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "cardinfowidget.h"
|
||||
#include "carditem.h"
|
||||
#include "carddatabase.h"
|
||||
#include "pictureloader.h"
|
||||
#include "main.h"
|
||||
#include "settingscache.h"
|
||||
|
||||
|
@ -195,10 +196,10 @@ void CardInfoWidget::updatePixmap()
|
|||
return;
|
||||
|
||||
QPixmap resizedPixmap;
|
||||
info->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio), resizedPixmap);
|
||||
PictureLoader::getPixmap(resizedPixmap, info, QSize(pixmapWidth, pixmapWidth * aspectRatio));
|
||||
|
||||
if (resizedPixmap.isNull())
|
||||
getCard()->getPixmap(QSize(pixmapWidth, pixmapWidth * aspectRatio), resizedPixmap);
|
||||
PictureLoader::getPixmap(resizedPixmap, getCard(), QSize(pixmapWidth, pixmapWidth * aspectRatio));
|
||||
cardPicture->setPixmap(resizedPixmap);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
}
|
||||
|
||||
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
|
||||
picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq());
|
||||
updateNotificationCheckBox.setChecked(settingsCache->getNotifyAboutUpdates());
|
||||
|
||||
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
|
||||
|
@ -53,20 +52,22 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
pixmapCacheEdit.setSingleStep(64);
|
||||
pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize());
|
||||
pixmapCacheEdit.setSuffix(" MB");
|
||||
picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq());
|
||||
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
|
||||
|
||||
highQualityURLEdit = new QLineEdit(settingsCache->getPicUrlHq());
|
||||
highQualityURLEdit->setEnabled(settingsCache->getPicDownloadHq());
|
||||
defaultUrlEdit = new QLineEdit(settingsCache->getPicUrl());
|
||||
fallbackUrlEdit = new QLineEdit(settingsCache->getPicUrlFallback());
|
||||
|
||||
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
|
||||
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(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(&picDownloadHqCheckBox, SIGNAL(clicked(bool)), this, SLOT(setEnabledStatus(bool)));
|
||||
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;
|
||||
personalGrid->addWidget(&languageLabel, 0, 0);
|
||||
|
@ -74,15 +75,18 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
personalGrid->addWidget(&pixmapCacheLabel, 1, 0);
|
||||
personalGrid->addWidget(&pixmapCacheEdit, 1, 1);
|
||||
personalGrid->addWidget(&updateNotificationCheckBox, 2, 0);
|
||||
personalGrid->addWidget(&picDownloadCheckBox, 3, 0);
|
||||
personalGrid->addWidget(&picDownloadHqCheckBox, 4, 0);
|
||||
personalGrid->addWidget(&highQualityURLLabel, 5, 0);
|
||||
personalGrid->addWidget(highQualityURLEdit, 5, 1);
|
||||
personalGrid->addWidget(&highQualityURLLinkLabel, 6, 1);
|
||||
personalGrid->addWidget(&clearDownloadedPicsButton, 6, 0);
|
||||
personalGrid->addWidget(&picDownloadCheckBox, 3, 0, 1, 3);
|
||||
personalGrid->addWidget(&defaultUrlLabel, 4, 0, 1, 1);
|
||||
personalGrid->addWidget(defaultUrlEdit, 4, 1, 1, 1);
|
||||
personalGrid->addWidget(&defaultUrlRestoreButton, 4, 2, 1, 1);
|
||||
personalGrid->addWidget(&fallbackUrlLabel, 5, 0, 1, 1);
|
||||
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);
|
||||
highQualityURLLinkLabel.setOpenExternalLinks(true);
|
||||
urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
urlLinkLabel.setOpenExternalLinks(true);
|
||||
|
||||
personalGroupBox = new QGroupBox;
|
||||
personalGroupBox->setLayout(personalGrid);
|
||||
|
@ -154,6 +158,20 @@ QString GeneralSettingsPage::languageName(const QString &qmFile)
|
|||
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()
|
||||
{
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Choose path"));
|
||||
|
@ -238,7 +256,6 @@ void GeneralSettingsPage::retranslateUi()
|
|||
personalGroupBox->setTitle(tr("Personal settings"));
|
||||
languageLabel.setText(tr("Language:"));
|
||||
picDownloadCheckBox.setText(tr("Download card pictures on the fly"));
|
||||
picDownloadHqCheckBox.setText(tr("Download card pictures from a custom URL"));
|
||||
pathsGroupBox->setTitle(tr("Paths"));
|
||||
deckPathLabel.setText(tr("Decks directory:"));
|
||||
replaysPathLabel.setText(tr("Replays directory:"));
|
||||
|
@ -246,15 +263,21 @@ void GeneralSettingsPage::retranslateUi()
|
|||
cardDatabasePathLabel.setText(tr("Card database:"));
|
||||
tokenDatabasePathLabel.setText(tr("Token database:"));
|
||||
pixmapCacheLabel.setText(tr("Picture cache size:"));
|
||||
highQualityURLLabel.setText(tr("Custom Card Download URL:"));
|
||||
highQualityURLLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(LINKING_FAQ_URL).arg(tr("Linking FAQ")));
|
||||
defaultUrlLabel.setText(tr("Primary download URL:"));
|
||||
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"));
|
||||
updateNotificationCheckBox.setText(tr("Notify when new client features are available"));
|
||||
defaultUrlRestoreButton.setText(tr("Reset"));
|
||||
fallbackUrlRestoreButton.setText(tr("Reset"));
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::setEnabledStatus(bool status)
|
||||
{
|
||||
highQualityURLEdit->setEnabled(status);
|
||||
defaultUrlEdit->setEnabled(status);
|
||||
fallbackUrlEdit->setEnabled(status);
|
||||
defaultUrlRestoreButton.setEnabled(status);
|
||||
fallbackUrlRestoreButton.setEnabled(status);
|
||||
}
|
||||
|
||||
AppearanceSettingsPage::AppearanceSettingsPage()
|
||||
|
|
|
@ -45,6 +45,8 @@ private slots:
|
|||
void tokenDatabasePathButtonClicked();
|
||||
void languageBoxChanged(int index);
|
||||
void setEnabledStatus(bool);
|
||||
void defaultUrlRestoreButtonClicked();
|
||||
void fallbackUrlRestoreButtonClicked();
|
||||
private:
|
||||
QStringList findQmFiles();
|
||||
QString languageName(const QString &qmFile);
|
||||
|
@ -53,13 +55,13 @@ private:
|
|||
QLineEdit *picsPathEdit;
|
||||
QLineEdit *cardDatabasePathEdit;
|
||||
QLineEdit *tokenDatabasePathEdit;
|
||||
QLineEdit *highQualityURLEdit;
|
||||
QLineEdit *defaultUrlEdit;
|
||||
QLineEdit *fallbackUrlEdit;
|
||||
QSpinBox pixmapCacheEdit;
|
||||
QGroupBox *personalGroupBox;
|
||||
QGroupBox *pathsGroupBox;
|
||||
QComboBox languageBox;
|
||||
QCheckBox picDownloadCheckBox;
|
||||
QCheckBox picDownloadHqCheckBox;
|
||||
QCheckBox updateNotificationCheckBox;
|
||||
QLabel languageLabel;
|
||||
QLabel pixmapCacheLabel;
|
||||
|
@ -68,9 +70,12 @@ private:
|
|||
QLabel picsPathLabel;
|
||||
QLabel cardDatabasePathLabel;
|
||||
QLabel tokenDatabasePathLabel;
|
||||
QLabel highQualityURLLabel;
|
||||
QLabel highQualityURLLinkLabel;
|
||||
QLabel defaultUrlLabel;
|
||||
QLabel fallbackUrlLabel;
|
||||
QLabel urlLinkLabel;
|
||||
QPushButton clearDownloadedPicsButton;
|
||||
QPushButton defaultUrlRestoreButton;
|
||||
QPushButton fallbackUrlRestoreButton;
|
||||
};
|
||||
|
||||
class AppearanceSettingsPage : public AbstractSettingsPage {
|
||||
|
|
450
cockatrice/src/pictureloader.cpp
Normal file
450
cockatrice/src/pictureloader.cpp
Normal 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);
|
||||
}
|
||||
}
|
78
cockatrice/src/pictureloader.h
Normal file
78
cockatrice/src/pictureloader.h
Normal 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
|
|
@ -165,12 +165,9 @@ SettingsCache::SettingsCache()
|
|||
pixmapCacheSize = PIXMAPCACHE_SIZE_DEFAULT;
|
||||
|
||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||
picDownloadHq = settings->value("personal/picturedownloadhq", true).toBool();
|
||||
|
||||
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();
|
||||
picUrlHqFallback = settings->value("personal/picUrlHqFallback", PIC_URL_HQ_FALLBACK).toString();
|
||||
|
||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||
|
@ -325,37 +322,18 @@ void SettingsCache::setPicDownload(int _picDownload)
|
|||
emit picDownloadChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setPicDownloadHq(int _picDownloadHq)
|
||||
{
|
||||
picDownloadHq = _picDownloadHq;
|
||||
settings->setValue("personal/picturedownloadhq", picDownloadHq);
|
||||
emit picDownloadHqChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setPicUrl(const QString &_picUrl)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
notificationsEnabled = _notificationsEnabled;
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
// 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_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
|
||||
#define PIXMAPCACHE_SIZE_DEFAULT 2047
|
||||
#define PIXMAPCACHE_SIZE_MIN 64
|
||||
|
@ -32,7 +30,6 @@ signals:
|
|||
void tokenDatabasePathChanged();
|
||||
void themeChanged();
|
||||
void picDownloadChanged();
|
||||
void picDownloadHqChanged();
|
||||
void displayCardNamesChanged();
|
||||
void horizontalHandChanged();
|
||||
void handJustificationChanged();
|
||||
|
@ -60,7 +57,6 @@ private:
|
|||
QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath, themeName;
|
||||
bool notifyAboutUpdates;
|
||||
bool picDownload;
|
||||
bool picDownloadHq;
|
||||
bool notificationsEnabled;
|
||||
bool spectatorNotificationsEnabled;
|
||||
bool doubleClickToPlay;
|
||||
|
@ -87,9 +83,7 @@ private:
|
|||
bool ignoreUnregisteredUsers;
|
||||
bool ignoreUnregisteredUserMessages;
|
||||
QString picUrl;
|
||||
QString picUrlHq;
|
||||
QString picUrlFallback;
|
||||
QString picUrlHqFallback;
|
||||
QString clientID;
|
||||
int pixmapCacheSize;
|
||||
bool scaleCards;
|
||||
|
@ -127,7 +121,6 @@ public:
|
|||
QString getChatMentionColor() const { return chatMentionColor; }
|
||||
QString getChatHighlightColor() const { return chatHighlightColor; }
|
||||
bool getPicDownload() const { return picDownload; }
|
||||
bool getPicDownloadHq() const { return picDownloadHq; }
|
||||
bool getNotificationsEnabled() const { return notificationsEnabled; }
|
||||
bool getSpectatorNotificationsEnabled() const { return spectatorNotificationsEnabled; }
|
||||
bool getNotifyAboutUpdates() const { return notifyAboutUpdates; }
|
||||
|
@ -160,9 +153,7 @@ public:
|
|||
bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; }
|
||||
bool getIgnoreUnregisteredUserMessages() const { return ignoreUnregisteredUserMessages; }
|
||||
QString getPicUrl() const { return picUrl; }
|
||||
QString getPicUrlHq() const { return picUrlHq; }
|
||||
QString getPicUrlFallback() const { return picUrlFallback; }
|
||||
QString getPicUrlHqFallback() const { return picUrlHqFallback; }
|
||||
int getPixmapCacheSize() const { return pixmapCacheSize; }
|
||||
bool getScaleCards() const { return scaleCards; }
|
||||
bool getShowMessagePopup() const { return showMessagePopups; }
|
||||
|
@ -204,7 +195,6 @@ public slots:
|
|||
void setChatMentionColor(const QString &_chatMentionColor);
|
||||
void setChatHighlightColor(const QString &_chatHighlightColor);
|
||||
void setPicDownload(int _picDownload);
|
||||
void setPicDownloadHq(int _picDownloadHq);
|
||||
void setNotificationsEnabled(int _notificationsEnabled);
|
||||
void setSpectatorNotificationsEnabled(int _spectatorNotificationsEnabled);
|
||||
void setDoubleClickToPlay(int _doubleClickToPlay);
|
||||
|
@ -231,9 +221,7 @@ public slots:
|
|||
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
|
||||
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
|
||||
void setPicUrl(const QString &_picUrl);
|
||||
void setPicUrlHq(const QString &_picUrlHq);
|
||||
void setPicUrlFallback(const QString &_picUrlFallback);
|
||||
void setPicUrlHqFallback(const QString &_picUrlHqFallback);
|
||||
void setPixmapCacheSize(const int _pixmapCacheSize);
|
||||
void setCardScaling(const int _scaleCards);
|
||||
void setShowMessagePopups(const int _showMessagePopups);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "tab_deck_editor.h"
|
||||
#include "window_sets.h"
|
||||
#include "carddatabase.h"
|
||||
#include "pictureloader.h"
|
||||
#include "carddatabasemodel.h"
|
||||
#include "decklistmodel.h"
|
||||
#include "cardinfowidget.h"
|
||||
|
@ -1058,7 +1059,7 @@ void TabDeckEditor::setDeck(DeckLoader *_deck)
|
|||
deckView->expandAll();
|
||||
setModified(false);
|
||||
|
||||
db->cacheCardPixmaps(deckModel->getDeckList()->getCardList());
|
||||
PictureLoader::cacheCardPixmaps(db->getCards(deckModel->getDeckList()->getCardList()));
|
||||
deckView->expandAll();
|
||||
setModified(false);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "main.h"
|
||||
#include "settingscache.h"
|
||||
#include "carddatabase.h"
|
||||
#include "pictureloader.h"
|
||||
#include "replay_timeline_widget.h"
|
||||
#include "lineeditcompleter.h"
|
||||
|
||||
|
@ -242,7 +243,7 @@ void DeckViewContainer::deckSelectFinished(const Response &r)
|
|||
{
|
||||
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
||||
DeckLoader newDeck(QString::fromStdString(resp.deck()));
|
||||
db->cacheCardPixmaps(newDeck.getCardList());
|
||||
PictureLoader::cacheCardPixmaps(db->getCards(newDeck.getCardList()));
|
||||
setDeck(newDeck);
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1045,7 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event, int /*e
|
|||
DeckViewContainer *deckViewContainer = deckViewContainers.value(playerId);
|
||||
if (playerInfo.has_deck_list()) {
|
||||
DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list()));
|
||||
db->cacheCardPixmaps(newDeck.getCardList());
|
||||
PictureLoader::cacheCardPixmaps(db->getCards(newDeck.getCardList()));
|
||||
deckViewContainer->setDeck(newDeck);
|
||||
player->setDeck(newDeck);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "window_sets.h"
|
||||
#include "setsmodel.h"
|
||||
#include "pictureloader.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <QTreeView>
|
||||
#include <QGridLayout>
|
||||
#include <QHeaderView>
|
||||
|
@ -123,7 +125,7 @@ WndSets::~WndSets()
|
|||
void WndSets::actSave()
|
||||
{
|
||||
model->save(db);
|
||||
db->clearPixmapCache();
|
||||
PictureLoader::clearPixmapCache();
|
||||
QMessageBox::information(this, tr("Success"), tr("The sets database has been saved successfully."));
|
||||
close();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
<xs:extension base="xs:string">
|
||||
<xs:attribute type="xs:int" name="muId" use="optional"/>
|
||||
<xs:attribute type="xs:anyURI" name="picUrl" use="optional"/>
|
||||
<xs:attribute type="xs:anyURI" name="picUrlHq" use="optional"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
|
|
@ -12,6 +12,7 @@ SET(oracle_SOURCES
|
|||
src/oraclewizard.cpp
|
||||
src/oracleimporter.cpp
|
||||
../cockatrice/src/carddatabase.cpp
|
||||
../cockatrice/src/pictureloader.cpp
|
||||
../cockatrice/src/settingscache.cpp
|
||||
../cockatrice/src/shortcutssettings.cpp
|
||||
../cockatrice/src/settings/carddatabasesettings.cpp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define ORACLEIMPORTER_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
|
||||
#include <carddatabase.h>
|
||||
|
||||
|
|
Loading…
Reference in a new issue