Several download URLs have arrived! (#3494)

* Cockatrice Picture loader uses better defined URLs now
URLs are defined on the Card Management tab
Instead of Primary/Backup, you can now define a list of URLs
List of URLs can be drag/dropped for priority ordering
Oracle now uses scryfallId > mtgjsonUUID for !uuid!

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* Simplify to QStringList and remove metacall

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* fix issues brought up by Dae. Also fix how the defaults load to account for first time users.

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* clangify

* Fix save settings on row moved (#3495)

* merge model fix, and reclangify

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>

* Sources > Resources

Signed-off-by: Zach Halpern <ZaHalpern+github@gmail.com>
This commit is contained in:
Zach H 2019-01-08 15:18:06 -05:00 committed by GitHub
parent 4eda7cda9e
commit b0e643ecc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 354 additions and 230 deletions

View file

@ -114,6 +114,7 @@ SET(cockatrice_SOURCES
src/settings/messagesettings.cpp src/settings/messagesettings.cpp
src/settings/gamefilterssettings.cpp src/settings/gamefilterssettings.cpp
src/settings/layoutssettings.cpp src/settings/layoutssettings.cpp
src/settings/downloadsettings.cpp
src/update_downloader.cpp src/update_downloader.cpp
src/logger.cpp src/logger.cpp
src/releasechannel.cpp src/releasechannel.cpp
@ -122,7 +123,7 @@ SET(cockatrice_SOURCES
src/handle_public_servers.cpp src/handle_public_servers.cpp
src/carddbparser/cockatricexml3.cpp src/carddbparser/cockatricexml3.cpp
${VERSION_STRING_CPP} ${VERSION_STRING_CPP}
) )
add_subdirectory(sounds) add_subdirectory(sounds)
add_subdirectory(themes) add_subdirectory(themes)

View file

@ -45,8 +45,6 @@ GeneralSettingsPage::GeneralSettingsPage()
languageBox.setCurrentIndex(i); languageBox.setCurrentIndex(i);
} }
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
// updates // updates
QList<ReleaseChannel *> channels = settingsCache->getUpdateReleaseChannels(); QList<ReleaseChannel *> channels = settingsCache->getUpdateReleaseChannels();
foreach (ReleaseChannel *chan, channels) { foreach (ReleaseChannel *chan, channels) {
@ -64,27 +62,15 @@ GeneralSettingsPage::GeneralSettingsPage()
pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize()); pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize());
pixmapCacheEdit.setSuffix(" MB"); pixmapCacheEdit.setSuffix(" MB");
defaultUrlEdit = new QLineEdit(settingsCache->getPicUrl());
fallbackUrlEdit = new QLineEdit(settingsCache->getPicUrlFallback());
showTipsOnStartup.setChecked(settingsCache->getShowTipsOnStartup()); showTipsOnStartup.setChecked(settingsCache->getShowTipsOnStartup());
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(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int))); connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int)));
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), settingsCache, connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), settingsCache,
SLOT(setUpdateReleaseChannel(int))); SLOT(setUpdateReleaseChannel(int)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int))); connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int)));
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()));
connect(&showTipsOnStartup, SIGNAL(clicked(bool)), settingsCache, SLOT(setShowTipsOnStartup(bool))); connect(&showTipsOnStartup, SIGNAL(clicked(bool)), settingsCache, SLOT(setShowTipsOnStartup(bool)));
setEnabledStatus(settingsCache->getPicDownload());
auto *personalGrid = new QGridLayout; auto *personalGrid = new QGridLayout;
personalGrid->addWidget(&languageLabel, 0, 0); personalGrid->addWidget(&languageLabel, 0, 0);
personalGrid->addWidget(&languageBox, 0, 1); personalGrid->addWidget(&languageBox, 0, 1);
@ -94,18 +80,6 @@ GeneralSettingsPage::GeneralSettingsPage()
personalGrid->addWidget(&pixmapCacheEdit, 2, 1); personalGrid->addWidget(&pixmapCacheEdit, 2, 1);
personalGrid->addWidget(&updateNotificationCheckBox, 3, 0); personalGrid->addWidget(&updateNotificationCheckBox, 3, 0);
personalGrid->addWidget(&showTipsOnStartup, 4, 0); personalGrid->addWidget(&showTipsOnStartup, 4, 0);
personalGrid->addWidget(&picDownloadCheckBox, 5, 0);
personalGrid->addWidget(&urlLinkLabel, 5, 1);
personalGrid->addWidget(&defaultUrlLabel, 6, 0, 1, 1);
personalGrid->addWidget(defaultUrlEdit, 6, 1, 1, 1);
personalGrid->addWidget(&defaultUrlRestoreButton, 6, 2, 1, 1);
personalGrid->addWidget(&fallbackUrlLabel, 7, 0, 1, 1);
personalGrid->addWidget(fallbackUrlEdit, 7, 1, 1, 1);
personalGrid->addWidget(&fallbackUrlRestoreButton, 7, 2, 1, 1);
personalGrid->addWidget(&clearDownloadedPicsButton, 8, 1);
urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
urlLinkLabel.setOpenExternalLinks(true);
personalGroupBox = new QGroupBox; personalGroupBox = new QGroupBox;
personalGroupBox->setLayout(personalGrid); personalGroupBox->setLayout(personalGrid);
@ -194,20 +168,6 @@ QString GeneralSettingsPage::languageName(const QString &qmFile)
return translator.translate("i18n", DEFAULT_LANG_NAME); return translator.translate("i18n", DEFAULT_LANG_NAME);
} }
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,30 +198,6 @@ void GeneralSettingsPage::picsPathButtonClicked()
settingsCache->setPicsPath(path); settingsCache->setPicsPath(path);
} }
void GeneralSettingsPage::clearDownloadedPicsButtonClicked()
{
QString picsPath = settingsCache->getPicsPath() + "/downloadedPics/";
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
bool outerSuccessRemove = true;
for (int i = 0; i < dirs.length(); i++) {
QString currentPath = picsPath + dirs.at(i) + "/";
QStringList files = QDir(currentPath).entryList(QDir::Files);
bool innerSuccessRemove = true;
for (int j = 0; j < files.length(); j++)
if (!QDir(currentPath).remove(files.at(j))) {
qDebug() << "Failed to remove " + currentPath.toUtf8() + files.at(j).toUtf8();
outerSuccessRemove = false;
innerSuccessRemove = false;
}
if (innerSuccessRemove)
QDir(picsPath).rmdir(dirs.at(i));
}
if (outerSuccessRemove)
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
else
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
}
void GeneralSettingsPage::cardDatabasePathButtonClicked() void GeneralSettingsPage::cardDatabasePathButtonClicked()
{ {
QString path = QFileDialog::getOpenFileName(this, tr("Choose path")); QString path = QFileDialog::getOpenFileName(this, tr("Choose path"));
@ -291,7 +227,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"));
if (settingsCache->getIsPortableBuild()) { if (settingsCache->getIsPortableBuild()) {
pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)")); pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
@ -305,26 +240,11 @@ 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:"));
defaultUrlLabel.setText(tr("Primary download URL:"));
fallbackUrlLabel.setText(tr("Fallback download URL:"));
urlLinkLabel.setText(
QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to set a custom picture url")));
clearDownloadedPicsButton.setText(tr("Reset/clear downloaded pictures"));
updateReleaseChannelLabel.setText(tr("Update channel")); updateReleaseChannelLabel.setText(tr("Update channel"));
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client")); updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
defaultUrlRestoreButton.setText(tr("Reset"));
fallbackUrlRestoreButton.setText(tr("Reset"));
showTipsOnStartup.setText(tr("Show tips on startup")); showTipsOnStartup.setText(tr("Show tips on startup"));
} }
void GeneralSettingsPage::setEnabledStatus(bool status)
{
defaultUrlEdit->setEnabled(status);
fallbackUrlEdit->setEnabled(status);
defaultUrlRestoreButton.setEnabled(status);
fallbackUrlRestoreButton.setEnabled(status);
}
AppearanceSettingsPage::AppearanceSettingsPage() AppearanceSettingsPage::AppearanceSettingsPage()
{ {
QString themeName = settingsCache->getThemeName(); QString themeName = settingsCache->getThemeName();
@ -498,6 +418,15 @@ void UserInterfaceSettingsPage::retranslateUi()
DeckEditorSettingsPage::DeckEditorSettingsPage() DeckEditorSettingsPage::DeckEditorSettingsPage()
{ {
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
urlLinkLabel.setOpenExternalLinks(true);
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
connect(&resetDownloadURLs, SIGNAL(clicked()), this, SLOT(resetDownloadedURLsButtonClicked()));
auto *lpGeneralGrid = new QGridLayout; auto *lpGeneralGrid = new QGridLayout;
auto *lpSpoilerGrid = new QGridLayout; auto *lpSpoilerGrid = new QGridLayout;
@ -515,9 +444,46 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
// Update the GUI depending on if the box is ticked or not // Update the GUI depending on if the box is ticked or not
setSpoilersEnabled(mcDownloadSpoilersCheckBox.isChecked()); setSpoilersEnabled(mcDownloadSpoilersCheckBox.isChecked());
// Create the layout urlList = new QListWidget;
lpGeneralGrid->addWidget(&mcGeneralMessageLabel, 0, 0); urlList->setSelectionMode(QAbstractItemView::SingleSelection);
urlList->setAlternatingRowColors(true);
urlList->setDragEnabled(true);
urlList->setDragDropMode(QAbstractItemView::InternalMove);
connect(urlList->model(), SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)), this,
SLOT(urlListChanged(const QModelIndex, int, int, const QModelIndex, int)));
for (int i = 0; i < settingsCache->downloads().getCount(); i++)
urlList->addItem(settingsCache->downloads().getDownloadUrlAt(i));
auto aAdd = new QAction(this);
aAdd->setIcon(QPixmap("theme:icons/increment"));
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAddURL()));
auto aEdit = new QAction(this);
aEdit->setIcon(QPixmap("theme:icons/pencil"));
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEditURL()));
auto aRemove = new QAction(this);
aRemove->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemoveURL()));
auto *messageToolBar = new QToolBar;
messageToolBar->setOrientation(Qt::Vertical);
messageToolBar->addAction(aAdd);
messageToolBar->addAction(aRemove);
messageToolBar->addAction(aEdit);
messageToolBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
auto *messageListLayout = new QHBoxLayout;
messageListLayout->addWidget(messageToolBar);
messageListLayout->addWidget(urlList);
// Top Layout
lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0);
lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1);
lpGeneralGrid->addLayout(messageListLayout, 1, 0, 1, 2);
lpGeneralGrid->addWidget(&urlLinkLabel, 2, 0);
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 2, 1);
// Spoiler Layout
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0); lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
lpSpoilerGrid->addWidget(&mcSpoilerSaveLabel, 1, 0); lpSpoilerGrid->addWidget(&mcSpoilerSaveLabel, 1, 0);
lpSpoilerGrid->addWidget(mpSpoilerSavePathLineEdit, 1, 1); lpSpoilerGrid->addWidget(mpSpoilerSavePathLineEdit, 1, 1);
@ -543,6 +509,94 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
setLayout(lpMainLayout); setLayout(lpMainLayout);
} }
void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked()
{
settingsCache->downloads().clear();
urlList->clear();
urlList->addItems(settingsCache->downloads().getAllURLs());
QMessageBox::information(this, tr("Success"), tr("Download URLs have been reset."));
}
void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
{
QString picsPath = settingsCache->getPicsPath() + "/downloadedPics/";
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
bool outerSuccessRemove = true;
for (const auto &dir : dirs) {
QString currentPath = picsPath + dir + "/";
QStringList files = QDir(currentPath).entryList(QDir::Files);
bool innerSuccessRemove = true;
for (int j = 0; j < files.length(); j++) {
if (!QDir(currentPath).remove(files.at(j))) {
qInfo() << "Failed to remove " + currentPath.toUtf8() + files.at(j).toUtf8();
outerSuccessRemove = false;
innerSuccessRemove = false;
}
qInfo() << "Removed " << currentPath << files.at(j);
}
if (innerSuccessRemove) {
bool success = QDir(picsPath).rmdir(dir);
if (!success) {
qInfo() << "Failed to remove inner directory" << picsPath;
} else {
qInfo() << "Removed" << currentPath;
}
}
}
if (outerSuccessRemove) {
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
} else {
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
}
}
void DeckEditorSettingsPage::actAddURL()
{
bool ok;
QString msg = QInputDialog::getText(this, tr("Add URL"), tr("URL:"), QLineEdit::Normal, QString(), &ok);
if (ok) {
urlList->addItem(msg);
storeSettings();
}
}
void DeckEditorSettingsPage::actRemoveURL()
{
if (urlList->currentItem() != nullptr) {
delete urlList->takeItem(urlList->currentRow());
storeSettings();
}
}
void DeckEditorSettingsPage::actEditURL()
{
if (urlList->currentItem()) {
QString oldText = urlList->currentItem()->text();
bool ok;
QString msg = QInputDialog::getText(this, tr("Edit URL"), tr("URL:"), QLineEdit::Normal, oldText, &ok);
if (ok) {
urlList->currentItem()->setText(msg);
storeSettings();
}
}
}
void DeckEditorSettingsPage::storeSettings()
{
qInfo() << "URL Priority Reset";
settingsCache->downloads().clear();
for (int i = 0; i < urlList->count(); i++) {
qInfo() << "Priority" << i << ":" << urlList->item(i)->text();
settingsCache->downloads().setDownloadUrlAt(i, urlList->item(i)->text());
}
}
void DeckEditorSettingsPage::urlListChanged(const QModelIndex &, int, int, const QModelIndex &, int)
{
storeSettings();
}
void DeckEditorSettingsPage::updateSpoilers() void DeckEditorSettingsPage::updateSpoilers()
{ {
// Disable the button so the user can only press it once at a time // Disable the button so the user can only press it once at a time
@ -603,14 +657,18 @@ void DeckEditorSettingsPage::setSpoilersEnabled(bool anInput)
void DeckEditorSettingsPage::retranslateUi() void DeckEditorSettingsPage::retranslateUi()
{ {
mpGeneralGroupBox->setTitle(tr("URL Download Priority"));
mpSpoilerGroupBox->setTitle(tr("Spoilers")); mpSpoilerGroupBox->setTitle(tr("Spoilers"));
mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically")); mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically"));
mcSpoilerSaveLabel.setText(tr("Spoiler Location:")); mcSpoilerSaveLabel.setText(tr("Spoiler Location:"));
mcGeneralMessageLabel.setText(tr("Hey, something's here finally!"));
lastUpdatedLabel.setText(tr("Last Updated") + ": " + getLastUpdateTime()); lastUpdatedLabel.setText(tr("Last Updated") + ": " + getLastUpdateTime());
infoOnSpoilersLabel.setText(tr("Spoilers download automatically on launch") + "\n" + infoOnSpoilersLabel.setText(tr("Spoilers download automatically on launch") + "\n" +
tr("Press the button to manually update without relaunching") + "\n\n" + tr("Press the button to manually update without relaunching") + "\n\n" +
tr("Do not close settings until manual update complete")); tr("Do not close settings until manual update complete"));
picDownloadCheckBox.setText(tr("Download card pictures on the fly"));
urlLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL")));
clearDownloadedPicsButton.setText(tr("Delete Downloaded Images"));
resetDownloadURLs.setText(tr("Reset Download URLs"));
} }
MessagesSettingsPage::MessagesSettingsPage() MessagesSettingsPage::MessagesSettingsPage()
@ -689,12 +747,16 @@ MessagesSettingsPage::MessagesSettingsPage()
aAdd = new QAction(this); aAdd = new QAction(this);
aAdd->setIcon(QPixmap("theme:icons/increment")); aAdd->setIcon(QPixmap("theme:icons/increment"));
aAdd->setStatusTip(tr("Add New URL"));
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAdd())); connect(aAdd, SIGNAL(triggered()), this, SLOT(actAdd()));
aEdit = new QAction(this); aEdit = new QAction(this);
aEdit->setIcon(QPixmap("theme:icons/pencil")); aEdit->setIcon(QPixmap("theme:icons/pencil"));
aEdit->setStatusTip(tr("Edit URL"));
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEdit())); connect(aEdit, SIGNAL(triggered()), this, SLOT(actEdit()));
aRemove = new QAction(this); aRemove = new QAction(this);
aRemove->setIcon(QPixmap("theme:icons/decrement")); aRemove->setIcon(QPixmap("theme:icons/decrement"));
aRemove->setStatusTip(tr("Remove URL"));
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove())); connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove()));
auto *messageToolBar = new QToolBar; auto *messageToolBar = new QToolBar;
@ -798,7 +860,7 @@ void MessagesSettingsPage::actEdit()
void MessagesSettingsPage::actRemove() void MessagesSettingsPage::actRemove()
{ {
if (messageList->currentItem()) { if (messageList->currentItem() != nullptr) {
delete messageList->takeItem(messageList->currentRow()); delete messageList->takeItem(messageList->currentRow());
storeSettings(); storeSettings();
} }
@ -1000,7 +1062,7 @@ void DlgSettings::setTab(int index)
void DlgSettings::updateLanguage() void DlgSettings::updateLanguage()
{ {
qApp->removeTranslator(translator); qApp->removeTranslator(translator); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
installNewTranslator(); installNewTranslator();
} }
@ -1094,7 +1156,7 @@ void DlgSettings::retranslateUi()
generalButton->setText(tr("General")); generalButton->setText(tr("General"));
appearanceButton->setText(tr("Appearance")); appearanceButton->setText(tr("Appearance"));
userInterfaceButton->setText(tr("User Interface")); userInterfaceButton->setText(tr("User Interface"));
deckEditorButton->setText(tr("Deck Editor")); deckEditorButton->setText(tr("Card Sources"));
messagesButton->setText(tr("Chat")); messagesButton->setText(tr("Chat"));
soundButton->setText(tr("Sound")); soundButton->setText(tr("Sound"));
shortcutsButton->setText(tr("Shortcuts")); shortcutsButton->setText(tr("Shortcuts"));

View file

@ -43,13 +43,9 @@ private slots:
void deckPathButtonClicked(); void deckPathButtonClicked();
void replaysPathButtonClicked(); void replaysPathButtonClicked();
void picsPathButtonClicked(); void picsPathButtonClicked();
void clearDownloadedPicsButtonClicked();
void cardDatabasePathButtonClicked(); void cardDatabasePathButtonClicked();
void tokenDatabasePathButtonClicked(); void tokenDatabasePathButtonClicked();
void languageBoxChanged(int index); void languageBoxChanged(int index);
void setEnabledStatus(bool);
void defaultUrlRestoreButtonClicked();
void fallbackUrlRestoreButtonClicked();
private: private:
QStringList findQmFiles(); QStringList findQmFiles();
@ -59,13 +55,10 @@ private:
QLineEdit *picsPathEdit; QLineEdit *picsPathEdit;
QLineEdit *cardDatabasePathEdit; QLineEdit *cardDatabasePathEdit;
QLineEdit *tokenDatabasePathEdit; QLineEdit *tokenDatabasePathEdit;
QLineEdit *defaultUrlEdit;
QLineEdit *fallbackUrlEdit;
QSpinBox pixmapCacheEdit; QSpinBox pixmapCacheEdit;
QGroupBox *personalGroupBox; QGroupBox *personalGroupBox;
QGroupBox *pathsGroupBox; QGroupBox *pathsGroupBox;
QComboBox languageBox; QComboBox languageBox;
QCheckBox picDownloadCheckBox;
QCheckBox updateNotificationCheckBox; QCheckBox updateNotificationCheckBox;
QComboBox updateReleaseChannelBox; QComboBox updateReleaseChannelBox;
QLabel languageLabel; QLabel languageLabel;
@ -75,13 +68,7 @@ private:
QLabel picsPathLabel; QLabel picsPathLabel;
QLabel cardDatabasePathLabel; QLabel cardDatabasePathLabel;
QLabel tokenDatabasePathLabel; QLabel tokenDatabasePathLabel;
QLabel defaultUrlLabel;
QLabel fallbackUrlLabel;
QLabel urlLinkLabel;
QLabel updateReleaseChannelLabel; QLabel updateReleaseChannelLabel;
QPushButton clearDownloadedPicsButton;
QPushButton defaultUrlRestoreButton;
QPushButton fallbackUrlRestoreButton;
QCheckBox showTipsOnStartup; QCheckBox showTipsOnStartup;
}; };
@ -143,19 +130,30 @@ public:
QString getLastUpdateTime(); QString getLastUpdateTime();
private slots: private slots:
void storeSettings();
void urlListChanged(const QModelIndex &, int, int, const QModelIndex &, int);
void setSpoilersEnabled(bool); void setSpoilersEnabled(bool);
void spoilerPathButtonClicked(); void spoilerPathButtonClicked();
void updateSpoilers(); void updateSpoilers();
void unlockSettings(); void unlockSettings();
void actAddURL();
void actRemoveURL();
void actEditURL();
void clearDownloadedPicsButtonClicked();
void resetDownloadedURLsButtonClicked();
private: private:
QPushButton clearDownloadedPicsButton;
QPushButton resetDownloadURLs;
QLabel urlLinkLabel;
QCheckBox picDownloadCheckBox;
QListWidget *urlList;
QCheckBox mcDownloadSpoilersCheckBox; QCheckBox mcDownloadSpoilersCheckBox;
QLabel msDownloadSpoilersLabel; QLabel msDownloadSpoilersLabel;
QGroupBox *mpGeneralGroupBox; QGroupBox *mpGeneralGroupBox;
QGroupBox *mpSpoilerGroupBox; QGroupBox *mpSpoilerGroupBox;
QLineEdit *mpSpoilerSavePathLineEdit; QLineEdit *mpSpoilerSavePathLineEdit;
QLabel mcSpoilerSaveLabel; QLabel mcSpoilerSaveLabel;
QLabel mcGeneralMessageLabel;
QLabel lastUpdatedLabel; QLabel lastUpdatedLabel;
QLabel infoOnSpoilersLabel; QLabel infoOnSpoilersLabel;
QPushButton *mpSpoilerPathButton; QPushButton *mpSpoilerPathButton;

View file

@ -25,35 +25,9 @@
// never cache more than 300 cards at once for a single deck // never cache more than 300 cards at once for a single deck
#define CACHED_CARD_PER_DECK_MAX 300 #define CACHED_CARD_PER_DECK_MAX 300
// Other URLs we can use (TODO: Make this less messy)
#define GATHERER_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
#define GATHERER_FALLBACK "http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"
class PictureToLoad::SetDownloadPriorityComparator
{
public:
/*
* Returns true if a has higher download priority than b
* Enabled sets have priority over disabled sets
* Both groups follows the user-defined order
*/
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a->getEnabled()) {
return !b->getEnabled() || a->getSortKey() < b->getSortKey();
} else {
return !b->getEnabled() && a->getSortKey() < b->getSortKey();
}
}
};
PictureToLoad::PictureToLoad(CardInfoPtr _card) : card(std::move(_card)) PictureToLoad::PictureToLoad(CardInfoPtr _card) : card(std::move(_card))
{ {
/* #2479 will expand this into a list of Urls */ urlTemplates = settingsCache->downloads().getAllURLs();
urlTemplates.append(settingsCache->getPicUrl());
urlTemplates.append(settingsCache->getPicUrlFallback());
urlTemplates.append(GATHERER_DEFAULT);
urlTemplates.append(GATHERER_FALLBACK);
if (card) { if (card) {
sortedSets = card->getSets(); sortedSets = card->getSets();
@ -78,7 +52,7 @@ void PictureToLoad::populateSetUrls()
} }
} }
foreach (QString urlTemplate, urlTemplates) { for (const QString &urlTemplate : urlTemplates) {
QString transformedUrl = transformUrl(urlTemplate); QString transformedUrl = transformUrl(urlTemplate);
if (!transformedUrl.isEmpty()) { if (!transformedUrl.isEmpty()) {
@ -121,10 +95,8 @@ QString PictureToLoad::getSetName() const
} }
} }
QStringList PictureLoaderWorker::md5Blacklist = QStringList() // Card back returned by gatherer when card is not found
<< "db0c48db407a907c16ade38de048a441"; // card back returned QStringList PictureLoaderWorker::md5Blacklist = QStringList() << "db0c48db407a907c16ade38de048a441";
// by gatherer when
// card is not found
PictureLoaderWorker::PictureLoaderWorker() : QObject(nullptr), downloadRunning(false), loadQueueRunning(false) PictureLoaderWorker::PictureLoaderWorker() : QObject(nullptr), downloadRunning(false), loadQueueRunning(false)
{ {
@ -151,12 +123,12 @@ PictureLoaderWorker::~PictureLoaderWorker()
void PictureLoaderWorker::processLoadQueue() void PictureLoaderWorker::processLoadQueue()
{ {
if (loadQueueRunning) if (loadQueueRunning) {
return; return;
}
loadQueueRunning = true; loadQueueRunning = true;
forever while (true) {
{
mutex.lock(); mutex.lock();
if (loadQueue.isEmpty()) { if (loadQueue.isEmpty()) {
mutex.unlock(); mutex.unlock();
@ -169,23 +141,26 @@ void PictureLoaderWorker::processLoadQueue()
QString setName = cardBeingLoaded.getSetName(); QString setName = cardBeingLoaded.getSetName();
QString cardName = cardBeingLoaded.getCard()->getName(); QString cardName = cardBeingLoaded.getCard()->getName();
QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName(); QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName();
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture"; qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture";
if (cardImageExistsOnDisk(setName, correctedCardName)) if (cardImageExistsOnDisk(setName, correctedCardName)) {
continue; continue;
}
if (picDownload) { if (picDownload) {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture not found on disk, trying to download"; << "]: Picture not found on disk, trying to download";
cardsToDownload.append(cardBeingLoaded); cardsToDownload.append(cardBeingLoaded);
cardBeingLoaded.clear(); cardBeingLoaded.clear();
if (!downloadRunning) if (!downloadRunning) {
startNextPicDownload(); startNextPicDownload();
}
} else { } else {
if (cardBeingLoaded.nextSet()) { if (cardBeingLoaded.nextSet()) {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture NOT found and download disabled, moving to next " << "]: Picture NOT found and download disabled, moving to next "
"set (newset: " "set (new set: "
<< setName << " card: " << cardName << ")"; << setName << " card: " << cardName << ")";
mutex.lock(); mutex.lock();
loadQueue.prepend(cardBeingLoaded); loadQueue.prepend(cardBeingLoaded);
@ -194,7 +169,7 @@ void PictureLoaderWorker::processLoadQueue()
} else { } else {
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
<< "]: Picture NOT found, download disabled, no more sets to " << "]: Picture NOT found, download disabled, no more sets to "
"try: BAILING OUT (oldset: " "try: BAILING OUT (old set: "
<< setName << " card: " << cardName << ")"; << setName << " card: " << cardName << ")";
imageLoaded(cardBeingLoaded.getCard(), QImage()); imageLoaded(cardBeingLoaded.getCard(), QImage());
} }
@ -227,22 +202,22 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
// Iterates through the list of paths, searching for images with the desired // Iterates through the list of paths, searching for images with the desired
// name with any QImageReader-supported // name with any QImageReader-supported
// extension // extension
for (int i = 0; i < picsPaths.length(); i++) { for (const auto &picsPath : picsPaths) {
imgReader.setFileName(picsPaths.at(i)); imgReader.setFileName(picsPath);
if (imgReader.read(&image)) { if (imgReader.read(&image)) {
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture found on disk."; << "]: Picture found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image); imageLoaded(cardBeingLoaded.getCard(), image);
return true; return true;
} }
imgReader.setFileName(picsPaths.at(i) + ".full"); imgReader.setFileName(picsPath + ".full");
if (imgReader.read(&image)) { if (imgReader.read(&image)) {
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.full found on disk."; << "]: Picture.full found on disk.";
imageLoaded(cardBeingLoaded.getCard(), image); imageLoaded(cardBeingLoaded.getCard(), image);
return true; return true;
} }
imgReader.setFileName(picsPaths.at(i) + ".xlhq"); imgReader.setFileName(picsPath + ".xlhq");
if (imgReader.read(&image)) { if (imgReader.read(&image)) {
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
<< "]: Picture.xlhq found on disk."; << "]: Picture.xlhq found on disk.";
@ -254,7 +229,7 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
return false; return false;
} }
QString PictureToLoad::transformUrl(QString urlTemplate) const QString PictureToLoad::transformUrl(const QString &urlTemplate) const
{ {
/* This function takes Url templates and substitutes actual card details /* This function takes Url templates and substitutes actual card details
into the url. This is used for making Urls with follow a predictable format into the url. This is used for making Urls with follow a predictable format
@ -289,7 +264,7 @@ QString PictureToLoad::transformUrl(QString urlTemplate) const
transformMap["!setname_lower!"] = QString(); transformMap["!setname_lower!"] = QString();
} }
foreach (QString prop, transformMap.keys()) { for (const QString &prop : transformMap.keys()) {
if (transformedUrl.contains(prop)) { if (transformedUrl.contains(prop)) {
if (!transformMap[prop].isEmpty()) { if (!transformMap[prop].isEmpty()) {
transformedUrl.replace(prop, QUrl::toPercentEncoding(transformMap[prop])); transformedUrl.replace(prop, QUrl::toPercentEncoding(transformMap[prop]));
@ -380,8 +355,8 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
return; return;
} }
const QByteArray &picData = reply->peek(reply->size()); // peek is used to keep the data in the buffer // peek is used to keep the data in the buffer for use by QImageReader
// for use by QImageReader const QByteArray &picData = reply->peek(reply->size());
if (imageIsBlackListed(picData)) { if (imageIsBlackListed(picData)) {
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName() qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
@ -403,8 +378,9 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
// prior to reading the // prior to reading the
// QImageReader data // QImageReader data
// into a QImage object, as that wipes the QImageReader buffer // into a QImage object, as that wipes the QImageReader buffer
if (extension == ".jpeg") if (extension == ".jpeg") {
extension = ".jpg"; extension = ".jpg";
}
if (imgReader.read(&testImage)) { if (imgReader.read(&testImage)) {
QString setName = cardBeingDownloaded.getSetName(); QString setName = cardBeingDownloaded.getSetName();
@ -418,8 +394,9 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" + QFile newPic(picsPath + "/downloadedPics/" + setName + "/" +
cardBeingDownloaded.getCard()->getCorrectedName() + extension); cardBeingDownloaded.getCard()->getCorrectedName() + extension);
if (!newPic.open(QIODevice::WriteOnly)) if (!newPic.open(QIODevice::WriteOnly)) {
return; return;
}
newPic.write(picData); newPic.write(picData);
newPic.close(); newPic.close();
} }
@ -444,15 +421,16 @@ void PictureLoaderWorker::enqueueImageLoad(CardInfoPtr card)
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
// avoid queueing the same card more than once // avoid queueing the same card more than once
if (!card || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard()) if (!card || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard()) {
return; return;
}
foreach (PictureToLoad pic, loadQueue) { for (const PictureToLoad &pic : loadQueue) {
if (pic.getCard() == card) if (pic.getCard() == card)
return; return;
} }
foreach (PictureToLoad pic, cardsToDownload) { for (const PictureToLoad &pic : cardsToDownload) {
if (pic.getCard() == card) if (pic.getCard() == card)
return; return;
} }
@ -474,7 +452,7 @@ void PictureLoaderWorker::picsPathChanged()
customPicsPath = settingsCache->getCustomPicsPath(); customPicsPath = settingsCache->getCustomPicsPath();
} }
PictureLoader::PictureLoader() : QObject(0) PictureLoader::PictureLoader() : QObject(nullptr)
{ {
worker = new PictureLoaderWorker; worker = new PictureLoaderWorker;
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged())); connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
@ -501,20 +479,21 @@ void PictureLoader::getCardBackPixmap(QPixmap &pixmap, QSize size)
void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size) void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
{ {
if (card == nullptr) if (card == nullptr) {
return; return;
}
// search for an exact size copy of the picure in cache // search for an exact size copy of the picure in cache
QString key = card->getPixmapCacheKey(); QString key = card->getPixmapCacheKey();
QString sizekey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height()); QString sizeKey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
if (QPixmapCache::find(sizekey, &pixmap)) if (QPixmapCache::find(sizeKey, &pixmap))
return; return;
// load the image and create a copy of the correct size // load the image and create a copy of the correct size
QPixmap bigPixmap; QPixmap bigPixmap;
if (QPixmapCache::find(key, &bigPixmap)) { if (QPixmapCache::find(key, &bigPixmap)) {
pixmap = bigPixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation); pixmap = bigPixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPixmapCache::insert(sizekey, pixmap); QPixmapCache::insert(sizeKey, pixmap);
return; return;
} }
@ -540,8 +519,9 @@ void PictureLoader::imageLoaded(CardInfoPtr card, const QImage &image)
void PictureLoader::clearPixmapCache(CardInfoPtr card) void PictureLoader::clearPixmapCache(CardInfoPtr card)
{ {
if (card) if (card) {
QPixmapCache::remove(card->getPixmapCacheKey()); QPixmapCache::remove(card->getPixmapCacheKey());
}
} }
void PictureLoader::clearPixmapCache() void PictureLoader::clearPixmapCache()
@ -554,13 +534,15 @@ void PictureLoader::cacheCardPixmaps(QList<CardInfoPtr> cards)
QPixmap tmp; QPixmap tmp;
int max = qMin(cards.size(), CACHED_CARD_PER_DECK_MAX); int max = qMin(cards.size(), CACHED_CARD_PER_DECK_MAX);
for (int i = 0; i < max; ++i) { for (int i = 0; i < max; ++i) {
CardInfoPtr card = cards.at(i); const CardInfoPtr &card = cards.at(i);
if (!card) if (!card) {
continue; continue;
}
QString key = card->getPixmapCacheKey(); QString key = card->getPixmapCacheKey();
if (QPixmapCache::find(key, &tmp)) if (QPixmapCache::find(key, &tmp)) {
continue; continue;
}
getInstance().worker->enqueueImageLoad(card); getInstance().worker->enqueueImageLoad(card);
} }

View file

@ -14,7 +14,23 @@ class QThread;
class PictureToLoad class PictureToLoad
{ {
private: private:
class SetDownloadPriorityComparator; class SetDownloadPriorityComparator
{
public:
/*
* Returns true if a has higher download priority than b
* Enabled sets have priority over disabled sets
* Both groups follows the user-defined order
*/
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
{
if (a->getEnabled()) {
return !b->getEnabled() || a->getSortKey() < b->getSortKey();
} else {
return !b->getEnabled() && a->getSortKey() < b->getSortKey();
}
}
};
CardInfoPtr card; CardInfoPtr card;
QList<CardSetPtr> sortedSets; QList<CardSetPtr> sortedSets;
@ -24,7 +40,8 @@ private:
CardSetPtr currentSet; CardSetPtr currentSet;
public: public:
PictureToLoad(CardInfoPtr _card = CardInfoPtr()); explicit PictureToLoad(CardInfoPtr _card = CardInfoPtr());
CardInfoPtr getCard() const CardInfoPtr getCard() const
{ {
return card; return card;
@ -42,7 +59,7 @@ public:
return currentSet; return currentSet;
} }
QString getSetName() const; QString getSetName() const;
QString transformUrl(QString urlTemplate) const; QString transformUrl(const QString &urlTemplate) const;
bool nextSet(); bool nextSet();
bool nextUrl(); bool nextUrl();
void populateSetUrls(); void populateSetUrls();
@ -52,8 +69,8 @@ class PictureLoaderWorker : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
PictureLoaderWorker(); explicit PictureLoaderWorker();
~PictureLoaderWorker(); ~PictureLoaderWorker() override;
void enqueueImageLoad(CardInfoPtr card); void enqueueImageLoad(CardInfoPtr card);
@ -70,8 +87,8 @@ private:
PictureToLoad cardBeingDownloaded; PictureToLoad cardBeingDownloaded;
bool picDownload, downloadRunning, loadQueueRunning; bool picDownload, downloadRunning, loadQueueRunning;
void startNextPicDownload(); void startNextPicDownload();
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardname); bool cardImageExistsOnDisk(QString &, QString &);
bool imageIsBlackListed(const QByteArray &picData); bool imageIsBlackListed(const QByteArray &);
private slots: private slots:
void picDownloadFinished(QNetworkReply *reply); void picDownloadFinished(QNetworkReply *reply);
void picDownloadFailed(); void picDownloadFailed();
@ -96,8 +113,8 @@ public:
} }
private: private:
PictureLoader(); explicit PictureLoader();
~PictureLoader(); ~PictureLoader() override;
// Singleton - Don't implement copy constructor and assign operator // Singleton - Don't implement copy constructor and assign operator
PictureLoader(PictureLoader const &); PictureLoader(PictureLoader const &);
void operator=(PictureLoader const &); void operator=(PictureLoader const &);

View file

@ -0,0 +1,56 @@
#include "downloadsettings.h"
#include "settingsmanager.h"
DownloadSettings::DownloadSettings(const QString &settingPath, QObject *parent = nullptr)
: SettingsManager(settingPath + "downloads.ini", parent)
{
downloadURLs = getValue("urls", "downloads").value<QStringList>();
}
void DownloadSettings::setDownloadUrlAt(int index, const QString &url)
{
downloadURLs.insert(index, url);
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
}
/**
* If reset or first run, this method contains the default URLs we will populate
*/
QStringList DownloadSettings::getAllURLs()
{
// First run, these will be empty
if (downloadURLs.count() == 0) {
populateDefaultURLs();
}
return downloadURLs;
}
void DownloadSettings::populateDefaultURLs()
{
downloadURLs.clear();
downloadURLs.append("https://api.scryfall.com/cards/!uuid!?format=image");
downloadURLs.append("https://api.scryfall.com/cards/multiverse/!cardid!?format=image");
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card");
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card");
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
}
QString DownloadSettings::getDownloadUrlAt(int index)
{
if (0 <= index && index < downloadURLs.size()) {
return downloadURLs[index];
}
return "";
}
int DownloadSettings::getCount()
{
return downloadURLs.size();
}
void DownloadSettings::clear()
{
downloadURLs.clear();
}

View file

@ -0,0 +1,28 @@
#ifndef COCKATRICE_DOWNLOADSETTINGS_H
#define COCKATRICE_DOWNLOADSETTINGS_H
#include "settingsmanager.h"
#include <QObject>
class DownloadSettings : public SettingsManager
{
Q_OBJECT
friend class SettingsCache;
public:
explicit DownloadSettings(const QString &, QObject *);
QStringList getAllURLs();
QString getDownloadUrlAt(int);
void setDownloadUrlAt(int, const QString &);
int getCount();
void clear();
private:
QStringList downloadURLs;
private:
void populateDefaultURLs();
};
#endif // COCKATRICE_DOWNLOADSETTINGS_H

View file

@ -164,6 +164,7 @@ SettingsCache::SettingsCache()
messageSettings = new MessageSettings(settingsPath, this); messageSettings = new MessageSettings(settingsPath, this);
gameFiltersSettings = new GameFiltersSettings(settingsPath, this); gameFiltersSettings = new GameFiltersSettings(settingsPath, this);
layoutsSettings = new LayoutsSettings(settingsPath, this); layoutsSettings = new LayoutsSettings(settingsPath, this);
downloadSettings = new DownloadSettings(settingsPath, this);
if (!QFile(settingsPath + "global.ini").exists()) if (!QFile(settingsPath + "global.ini").exists())
translateLegacySettings(); translateLegacySettings();
@ -220,9 +221,6 @@ SettingsCache::SettingsCache()
picDownload = settings->value("personal/picturedownload", true).toBool(); picDownload = settings->value("personal/picturedownload", true).toBool();
picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString();
picUrlFallback = settings->value("personal/picUrlFallback", PIC_URL_FALLBACK).toString();
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray(); mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray(); tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray();
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool(); notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
@ -415,18 +413,6 @@ void SettingsCache::setPicDownload(int _picDownload)
emit picDownloadChanged(); emit picDownloadChanged();
} }
void SettingsCache::setPicUrl(const QString &_picUrl)
{
picUrl = _picUrl;
settings->setValue("personal/picUrl", picUrl);
}
void SettingsCache::setPicUrlFallback(const QString &_picUrlFallback)
{
picUrlFallback = _picUrlFallback;
settings->setValue("personal/picUrlFallback", picUrlFallback);
}
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled) void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
{ {
notificationsEnabled = static_cast<bool>(_notificationsEnabled); notificationsEnabled = static_cast<bool>(_notificationsEnabled);

View file

@ -2,6 +2,7 @@
#define SETTINGSCACHE_H #define SETTINGSCACHE_H
#include "settings/carddatabasesettings.h" #include "settings/carddatabasesettings.h"
#include "settings/downloadsettings.h"
#include "settings/gamefilterssettings.h" #include "settings/gamefilterssettings.h"
#include "settings/layoutssettings.h" #include "settings/layoutssettings.h"
#include "settings/messagesettings.h" #include "settings/messagesettings.h"
@ -13,10 +14,6 @@
class ReleaseChannel; class ReleaseChannel;
// Fallbacks used for cards w/o MultiverseId
#define PIC_URL_DEFAULT "https://api.scryfall.com/cards/multiverse/!cardid!?format=image"
#define PIC_URL_FALLBACK "https://api.scryfall.com/cards/named?fuzzy=!name!&format=image"
// 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
@ -61,6 +58,7 @@ private:
MessageSettings *messageSettings; MessageSettings *messageSettings;
GameFiltersSettings *gameFiltersSettings; GameFiltersSettings *gameFiltersSettings;
LayoutsSettings *layoutsSettings; LayoutsSettings *layoutsSettings;
DownloadSettings *downloadSettings;
QByteArray mainWindowGeometry; QByteArray mainWindowGeometry;
QByteArray tokenDialogGeometry; QByteArray tokenDialogGeometry;
@ -303,14 +301,6 @@ public:
{ {
return ignoreUnregisteredUserMessages; return ignoreUnregisteredUserMessages;
} }
QString getPicUrl() const
{
return picUrl;
}
QString getPicUrlFallback() const
{
return picUrlFallback;
}
int getPixmapCacheSize() const int getPixmapCacheSize() const
{ {
return pixmapCacheSize; return pixmapCacheSize;
@ -430,6 +420,10 @@ public:
{ {
return *layoutsSettings; return *layoutsSettings;
} }
DownloadSettings &downloads() const
{
return *downloadSettings;
}
bool getIsPortableBuild() const bool getIsPortableBuild() const
{ {
return isPortableBuild; return isPortableBuild;
@ -478,8 +472,6 @@ public slots:
void setSoundThemeName(const QString &_soundThemeName); void setSoundThemeName(const QString &_soundThemeName);
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers); void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages); void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
void setPicUrl(const QString &_picUrl);
void setPicUrlFallback(const QString &_picUrlFallback);
void setPixmapCacheSize(const int _pixmapCacheSize); void setPixmapCacheSize(const int _pixmapCacheSize);
void setCardScaling(const int _scaleCards); void setCardScaling(const int _scaleCards);
void setShowMessagePopups(const int _showMessagePopups); void setShowMessagePopups(const int _showMessagePopups);

View file

@ -22,6 +22,7 @@ SET(oracle_SOURCES
../cockatrice/src/settings/messagesettings.cpp ../cockatrice/src/settings/messagesettings.cpp
../cockatrice/src/settings/gamefilterssettings.cpp ../cockatrice/src/settings/gamefilterssettings.cpp
../cockatrice/src/settings/layoutssettings.cpp ../cockatrice/src/settings/layoutssettings.cpp
../cockatrice/src/settings/downloadsettings.cpp
../cockatrice/src/thememanager.cpp ../cockatrice/src/thememanager.cpp
../cockatrice/src/qt-json/json.cpp ../cockatrice/src/qt-json/json.cpp
../cockatrice/src/releasechannel.cpp ../cockatrice/src/releasechannel.cpp

View file

@ -34,7 +34,7 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationName("Cockatrice"); QCoreApplication::setOrganizationName("Cockatrice");
QCoreApplication::setOrganizationDomain("cockatrice"); QCoreApplication::setOrganizationDomain("cockatrice");
// this can't be changed, as it influences the default savepath for cards.xml // this can't be changed, as it influences the default save path for cards.xml
QCoreApplication::setApplicationName("Cockatrice"); QCoreApplication::setApplicationName("Cockatrice");
// If the program is opened with the -s flag, it will only do spoilers. Otherwise it will do MTGJSON/Tokens // If the program is opened with the -s flag, it will only do spoilers. Otherwise it will do MTGJSON/Tokens

View file

@ -97,7 +97,7 @@ CardInfoPtr OracleImporter::addCard(const QString &setName,
bool mArtifact = false; bool mArtifact = false;
if (cardType.endsWith("Artifact")) { if (cardType.endsWith("Artifact")) {
for (int i = 0; i < cardTextRows.size(); ++i) { for (int i = 0; i < cardTextRows.size(); ++i) {
cardTextRows[i].remove(QRegularExpression("\\\".*?\\\"")); cardTextRows[i].remove(QRegularExpression(R"(\".*?\")"));
if (cardTextRows[i].contains("{T}") && cardTextRows[i].contains("to your mana pool")) { if (cardTextRows[i].contains("{T}") && cardTextRows[i].contains("to your mana pool")) {
mArtifact = true; mArtifact = true;
} }
@ -124,6 +124,7 @@ CardInfoPtr OracleImporter::addCard(const QString &setName,
cards.insert(cardName, card); cards.insert(cardName, card);
} }
card->setMuId(setName, cardId); card->setMuId(setName, cardId);
card->setUuId(setName, cardUuId); card->setUuId(setName, cardUuId);
card->setSetNumber(setName, setNumber); card->setSetNumber(setName, setNumber);
@ -152,7 +153,7 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
QString setNumber; QString setNumber;
QString rarity; QString rarity;
QString cardLoyalty; QString cardLoyalty;
bool upsideDown = false; bool upsideDown;
QMap<int, QVariantMap> splitCards; QMap<int, QVariantMap> splitCards;
while (it.hasNext()) { while (it.hasNext()) {
@ -187,14 +188,14 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
: QString(""); : QString("");
cardText = map.contains("text") ? map.value("text").toString() : QString(""); cardText = map.contains("text") ? map.value("text").toString() : QString("");
cardId = map.contains("multiverseId") ? map.value("multiverseId").toInt() : 0; cardId = map.contains("multiverseId") ? map.value("multiverseId").toInt() : 0;
cardUuId = map.contains("uuid") ? map.value("uuid").toString() : QString(""); cardUuId = map.contains("scryfallId") ? map.value("scryfallId").toString() : QString("");
setNumber = map.contains("number") ? map.value("number").toString() : QString(""); setNumber = map.contains("number") ? map.value("number").toString() : QString("");
rarity = map.contains("rarity") ? map.value("rarity").toString() : QString(""); rarity = map.contains("rarity") ? map.value("rarity").toString() : QString("");
cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toString() : QString(""); cardLoyalty = map.contains("loyalty") ? map.value("loyalty").toString() : QString("");
colors = map.contains("colors") ? map.value("colors").toStringList() : QStringList(); colors = map.contains("colors") ? map.value("colors").toStringList() : QStringList();
relatedCards = QList<CardRelation *>(); relatedCards = QList<CardRelation *>();
if (map.contains("names")) if (map.contains("names"))
foreach (const QString &name, map.value("names").toStringList()) { for (const QString &name : map.value("names").toStringList()) {
if (name != cardName) if (name != cardName)
relatedCards.append(new CardRelation(name, true)); relatedCards.append(new CardRelation(name, true));
} }
@ -218,18 +219,18 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
// split cards handling - get all unique card muids // split cards handling - get all unique card muids
QList<int> muids = splitCards.uniqueKeys(); QList<int> muids = splitCards.uniqueKeys();
foreach (int muid, muids) { for (int muid : muids) {
// get all cards for this specific muid // get all cards for this specific muid
QList<QVariantMap> maps = splitCards.values(muid); QList<QVariantMap> maps = splitCards.values(muid);
QStringList names; QStringList names;
// now, reorder the cards using the ordered list of names // now, reorder the cards using the ordered list of names
QMap<int, QVariantMap> orderedMaps; QMap<int, QVariantMap> orderedMaps;
foreach (QVariantMap map, maps) { for (const QVariantMap &inner_map : maps) {
if (names.isEmpty()) if (names.isEmpty())
names = map.contains("names") ? map.value("names").toStringList() : QStringList(); names = inner_map.contains("names") ? inner_map.value("names").toStringList() : QStringList();
QString name = map.value("name").toString(); QString name = inner_map.value("name").toString();
int index = names.indexOf(name); int index = names.indexOf(name);
orderedMaps.insertMulti(index, map); orderedMaps.insertMulti(index, inner_map);
} }
// clean variables // clean variables
@ -248,51 +249,51 @@ int OracleImporter::importTextSpoiler(CardSetPtr set, const QVariant &data)
// loop cards and merge their contents // loop cards and merge their contents
QString prefix = QString(" // "); QString prefix = QString(" // ");
QString prefix2 = QString("\n\n---\n\n"); QString prefix2 = QString("\n\n---\n\n");
foreach (QVariantMap map, orderedMaps.values()) { for (const QVariantMap &inner_map : orderedMaps.values()) {
if (map.contains("name")) { if (inner_map.contains("name")) {
if (!cardName.isEmpty()) if (!cardName.isEmpty())
cardName += (orderedMaps.count() > 2) ? QString("/") : prefix; cardName += (orderedMaps.count() > 2) ? QString("/") : prefix;
cardName += map.value("name").toString(); cardName += inner_map.value("name").toString();
} }
if (map.contains("manaCost")) { if (inner_map.contains("manaCost")) {
if (!cardCost.isEmpty()) if (!cardCost.isEmpty())
cardCost += prefix; cardCost += prefix;
cardCost += map.value("manaCost").toString(); cardCost += inner_map.value("manaCost").toString();
} }
if (map.contains("convertedManaCost")) { if (inner_map.contains("convertedManaCost")) {
if (!cmc.isEmpty()) if (!cmc.isEmpty())
cmc += prefix; cmc += prefix;
cmc += map.value("convertedManaCost").toString(); cmc += inner_map.value("convertedManaCost").toString();
} }
if (map.contains("type")) { if (inner_map.contains("type")) {
if (!cardType.isEmpty()) if (!cardType.isEmpty())
cardType += prefix; cardType += prefix;
cardType += map.value("type").toString(); cardType += inner_map.value("type").toString();
} }
if (map.contains("power") || map.contains("toughness")) { if (inner_map.contains("power") || inner_map.contains("toughness")) {
if (!cardPT.isEmpty()) if (!cardPT.isEmpty())
cardPT += prefix; cardPT += prefix;
cardPT += map.value("power").toString() + QString('/') + map.value("toughness").toString(); cardPT += inner_map.value("power").toString() + QString('/') + inner_map.value("toughness").toString();
} }
if (map.contains("text")) { if (inner_map.contains("text")) {
if (!cardText.isEmpty()) if (!cardText.isEmpty())
cardText += prefix2; cardText += prefix2;
cardText += map.value("text").toString(); cardText += inner_map.value("text").toString();
} }
if (map.contains("uuid")) { if (inner_map.contains("uuid")) {
if (cardUuId.isEmpty()) if (cardUuId.isEmpty())
cardUuId = map.value("uuid").toString(); cardUuId = inner_map.value("uuid").toString();
} }
if (map.contains("number")) { if (inner_map.contains("number")) {
if (setNumber.isEmpty()) if (setNumber.isEmpty())
setNumber = map.value("number").toString(); setNumber = inner_map.value("number").toString();
} }
if (map.contains("rarity")) { if (inner_map.contains("rarity")) {
if (rarity.isEmpty()) if (rarity.isEmpty())
rarity = map.value("rarity").toString(); rarity = inner_map.value("rarity").toString();
} }
colors << map.value("colors").toStringList(); colors << inner_map.value("colors").toStringList();
} }
colors.removeDuplicates(); colors.removeDuplicates();