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/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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 *)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
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;
|
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define ORACLEIMPORTER_H
|
#define ORACLEIMPORTER_H
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
#include <carddatabase.h>
|
#include <carddatabase.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue