diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt
index 29570fbd..52159ef4 100644
--- a/cockatrice/CMakeLists.txt
+++ b/cockatrice/CMakeLists.txt
@@ -19,6 +19,8 @@ SET(cockatrice_SOURCES
src/dlg_forgotpasswordreset.cpp
src/dlg_forgotpasswordchallenge.cpp
src/dlg_register.cpp
+ src/dlg_tip_of_the_day.cpp
+ src/tip_of_the_day.cpp
src/dlg_update.cpp
src/dlg_viewlog.cpp
src/abstractclient.cpp
diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc
index 5a98240c..432a9fa7 100644
--- a/cockatrice/cockatrice.qrc
+++ b/cockatrice/cockatrice.qrc
@@ -342,5 +342,19 @@
resources/userlevels/admin_vip.svg
resources/userlevels/admin_vip_buddy.svg
+
+ resources/tips/tips_of_the_day.xml
+ resources/tips/images/accounts_tab.png
+ resources/tips/images/arrows.png
+ resources/tips/images/cockatrice_register.png
+ resources/tips/images/cockatrice_wiki.png
+ resources/tips/images/coin_flip.png
+ resources/tips/images/face_down.png
+ resources/tips/images/filter_games.png
+ resources/tips/images/github_logo.png
+ resources/tips/images/gitter.png
+ resources/tips/images/themes.png
+ resources/tips/images/tip_of_the_day.png
+
diff --git a/cockatrice/resources/tips/images/accounts_tab.png b/cockatrice/resources/tips/images/accounts_tab.png
new file mode 100644
index 00000000..e8cb67af
Binary files /dev/null and b/cockatrice/resources/tips/images/accounts_tab.png differ
diff --git a/cockatrice/resources/tips/images/arrows.png b/cockatrice/resources/tips/images/arrows.png
new file mode 100644
index 00000000..a7b44dff
Binary files /dev/null and b/cockatrice/resources/tips/images/arrows.png differ
diff --git a/cockatrice/resources/tips/images/cockatrice_register.png b/cockatrice/resources/tips/images/cockatrice_register.png
new file mode 100644
index 00000000..f98d4e37
Binary files /dev/null and b/cockatrice/resources/tips/images/cockatrice_register.png differ
diff --git a/cockatrice/resources/tips/images/cockatrice_wiki.png b/cockatrice/resources/tips/images/cockatrice_wiki.png
new file mode 100644
index 00000000..df29e437
Binary files /dev/null and b/cockatrice/resources/tips/images/cockatrice_wiki.png differ
diff --git a/cockatrice/resources/tips/images/coin_flip.png b/cockatrice/resources/tips/images/coin_flip.png
new file mode 100644
index 00000000..b25e7d68
Binary files /dev/null and b/cockatrice/resources/tips/images/coin_flip.png differ
diff --git a/cockatrice/resources/tips/images/face_down.png b/cockatrice/resources/tips/images/face_down.png
new file mode 100644
index 00000000..f1e0782a
Binary files /dev/null and b/cockatrice/resources/tips/images/face_down.png differ
diff --git a/cockatrice/resources/tips/images/filter_games.png b/cockatrice/resources/tips/images/filter_games.png
new file mode 100644
index 00000000..de4eb7fd
Binary files /dev/null and b/cockatrice/resources/tips/images/filter_games.png differ
diff --git a/cockatrice/resources/tips/images/github_logo.png b/cockatrice/resources/tips/images/github_logo.png
new file mode 100644
index 00000000..49215c49
Binary files /dev/null and b/cockatrice/resources/tips/images/github_logo.png differ
diff --git a/cockatrice/resources/tips/images/gitter.png b/cockatrice/resources/tips/images/gitter.png
new file mode 100644
index 00000000..54e806d1
Binary files /dev/null and b/cockatrice/resources/tips/images/gitter.png differ
diff --git a/cockatrice/resources/tips/images/themes.png b/cockatrice/resources/tips/images/themes.png
new file mode 100644
index 00000000..9b5efb86
Binary files /dev/null and b/cockatrice/resources/tips/images/themes.png differ
diff --git a/cockatrice/resources/tips/images/tip_of_the_day.png b/cockatrice/resources/tips/images/tip_of_the_day.png
new file mode 100644
index 00000000..1b191986
Binary files /dev/null and b/cockatrice/resources/tips/images/tip_of_the_day.png differ
diff --git a/cockatrice/resources/tips/tips_of_the_day.xml b/cockatrice/resources/tips/tips_of_the_day.xml
new file mode 100644
index 00000000..5625fbe0
--- /dev/null
+++ b/cockatrice/resources/tips/tips_of_the_day.xml
@@ -0,0 +1,86 @@
+
+
+ Tip of the Day
+ Tip of the Day is a new feature to Cockatrice that allows users to get information about the newest features of the program and some of the most commonly asked questions!
+ tip_of_the_day.png
+ 2018-03-01
+
+
+ Suggesting New Tips
+ You can suggest new Tips of the Day by reaching out to the development team on <a href="https://gitter.im/cockatrice/cockatrice">Gitter</a>!
+ gitter.png
+ 2018-03-01
+
+
+ Reporting Bugs
+ If you encounter a bug while using Cockatrice, you can report the bug to the development team via <a href="https://github.com/cockatrice/cockatrice/issues">GitHub<a>
+ github_logo.png
+ 2018-03-01
+
+
+ FAQ/Troubleshooting Wiki
+ You can find answers to the most common questions and some helpful Cockatrice toubleshooting over on the <a href="https://github.com/cockatrice/cockatrice/wiki">GitHub wiki<a>
+ cockatrice_wiki.png
+ 2018-03-01
+
+
+ Register for a Server
+ Click on either Cockatrice (Windows) or Actions (Mac) and then Register to server... When the dialogue appears, fill out the desired server information.
+ cockatrice_register.png
+ 2018-03-01
+
+
+ Drawing Arrows
+ You can draw arrows of different color by holding a combination of keys!
+ Right Click: Red Arrow
+ Shift + Right Click: Green Arrow
+ Alt + Right Click: Blue Arrow
+ Cmd + Right Click: Yellow Arrow
+
+ arrows.png
+ 2018-03-01
+
+
+ Filtering Games
+ Don't see all the active games? Want to see a smaller selection? Use the Game Filters to change your horizon
+ filter_games.png
+ 2018-03-01
+
+
+ Upload Custom Avatar
+ Want to show off your hippo avatar? Need to update your password? Check out the Accounts Tab for more info!
+ accounts_tab.png
+ 2018-03-01
+
+
+ Common Shortcuts
+ You can find a full list of shortcuts <a href="https://github.com/Cockatrice/Cockatrice/wiki/Custom-Keyboard-Shortcuts">on the wiki</a>, but a short list:
+ <br>Roll a die: CTRL + I
+ <br>Mulligan: CTRL + M
+ <br>Draw a card: CTRL + D
+ <br>Undo a draw: CTRL + SHIFT + D
+ <br>View Sideboard: CTRL + F3
+ <br>Change Life: CTRL + L
+ <br>All shortcuts can be customized via Settings->Shortcuts!
+
+ 2018-03-01
+
+
+ Changing Themes
+ Did you know Cockatrice has custom themes? You can either <a href="https://github.com/Cockatrice/Cockatrice/wiki/Themes">create one yourself</a> or use one of the several pre-loaded ones! Go to Settings->Appearance and try them out!
+ themes.png
+ 2018-03-01
+
+
+ Flip of the Coin
+ You can flip a coin instead of rolling a die by rolling a 2 sided die instead!
+ coin_flip.png
+ 2018-03-01
+
+
+ Face Down Cards
+ You can hold Shift while dragging or clicking on a card to have it enter play face down
+ face_down.png
+ 2018-03-01
+
+
\ No newline at end of file
diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp
index 80a93746..8e97fe55 100644
--- a/cockatrice/src/dlg_settings.cpp
+++ b/cockatrice/src/dlg_settings.cpp
@@ -67,6 +67,8 @@ GeneralSettingsPage::GeneralSettingsPage()
defaultUrlEdit = new QLineEdit(settingsCache->getPicUrl());
fallbackUrlEdit = new QLineEdit(settingsCache->getPicUrlFallback());
+ showTipsOnStartup.setChecked(settingsCache->getShowTipsOnStartup());
+
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
@@ -79,6 +81,7 @@ GeneralSettingsPage::GeneralSettingsPage()
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)));
setEnabledStatus(settingsCache->getPicDownload());
@@ -97,6 +100,7 @@ GeneralSettingsPage::GeneralSettingsPage()
personalGrid->addWidget(&fallbackUrlLabel, 6, 0, 1, 1);
personalGrid->addWidget(fallbackUrlEdit, 6, 1, 1, 1);
personalGrid->addWidget(&fallbackUrlRestoreButton, 6, 2, 1, 1);
+ personalGrid->addWidget(&showTipsOnStartup, 7, 0);
personalGrid->addWidget(&urlLinkLabel, 7, 1, 1, 1);
personalGrid->addWidget(&clearDownloadedPicsButton, 8, 0, 1, 3);
@@ -310,6 +314,7 @@ void GeneralSettingsPage::retranslateUi()
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"));
}
void GeneralSettingsPage::setEnabledStatus(bool status)
diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h
index 75da474b..6f02086f 100644
--- a/cockatrice/src/dlg_settings.h
+++ b/cockatrice/src/dlg_settings.h
@@ -82,6 +82,7 @@ private:
QPushButton clearDownloadedPicsButton;
QPushButton defaultUrlRestoreButton;
QPushButton fallbackUrlRestoreButton;
+ QCheckBox showTipsOnStartup;
};
class AppearanceSettingsPage : public AbstractSettingsPage
diff --git a/cockatrice/src/dlg_tip_of_the_day.cpp b/cockatrice/src/dlg_tip_of_the_day.cpp
new file mode 100644
index 00000000..0bb78f07
--- /dev/null
+++ b/cockatrice/src/dlg_tip_of_the_day.cpp
@@ -0,0 +1,153 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dlg_tip_of_the_day.h"
+#include "settingscache.h"
+#include "tip_of_the_day.h"
+
+#define MIN_TIP_IMAGE_HEIGHT 200
+#define MIN_TIP_IMAGE_WIDTH 200
+#define MAX_TIP_IMAGE_HEIGHT 300
+#define MAX_TIP_IMAGE_WIDTH 300
+
+DlgTipOfTheDay::DlgTipOfTheDay(QWidget *parent) : QDialog(parent)
+{
+ successfulInit = false;
+ QString xmlPath = "theme:tips/tips_of_the_day.xml";
+ tipDatabase = new TipsOfTheDay(xmlPath, this);
+
+ if (tipDatabase->rowCount() == 0) {
+ return;
+ }
+
+ title = new QLabel();
+ title->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ tipTextContent = new QLabel();
+ tipTextContent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ tipTextContent->setWordWrap(true);
+ tipTextContent->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ tipTextContent->setOpenExternalLinks(true);
+ imageLabel = new QLabel();
+ imageLabel->setFixedHeight(MAX_TIP_IMAGE_HEIGHT + 50);
+ imageLabel->setFixedWidth(MAX_TIP_IMAGE_WIDTH + 50);
+ image = new QPixmap();
+ date = new QLabel();
+ date->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ tipNumber = new QLabel();
+ tipNumber->setAlignment(Qt::AlignCenter);
+
+ currentTip = settingsCache->getLastShownTip() + 1;
+ connect(this, SIGNAL(newTipRequested(int)), this, SLOT(updateTip(int)));
+ newTipRequested(currentTip);
+
+ content = new QVBoxLayout;
+ content->addWidget(title);
+ content->addWidget(tipTextContent);
+ content->addWidget(imageLabel);
+ content->addWidget(date);
+
+ buttonBox = new QDialogButtonBox(Qt::Horizontal);
+ nextButton = new QPushButton(tr("Next"));
+ previousButton = new QPushButton(tr("Previous"));
+ buttonBox->addButton(previousButton, QDialogButtonBox::ActionRole);
+ buttonBox->addButton(nextButton, QDialogButtonBox::ActionRole);
+ buttonBox->addButton(QDialogButtonBox::Ok);
+ buttonBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(nextButton, SIGNAL(clicked()), this, SLOT(nextClicked()));
+ connect(previousButton, SIGNAL(clicked()), this, SLOT(previousClicked()));
+
+ showTipsOnStartupCheck = new QCheckBox("Show tips on startup");
+ showTipsOnStartupCheck->setChecked(true);
+ connect(showTipsOnStartupCheck, SIGNAL(clicked(bool)), settingsCache, SLOT(setShowTipsOnStartup(bool)));
+ buttonBar = new QHBoxLayout();
+ buttonBar->addWidget(showTipsOnStartupCheck);
+ buttonBar->addWidget(tipNumber);
+ buttonBar->addWidget(buttonBox);
+
+ mainLayout = new QVBoxLayout;
+ mainLayout->addLayout(content);
+ mainLayout->addLayout(buttonBar);
+ setLayout(mainLayout);
+
+ setWindowTitle(tr("Tip of the Day"));
+ setMinimumWidth(500);
+ setMinimumHeight(300);
+ successfulInit = true;
+}
+
+DlgTipOfTheDay::~DlgTipOfTheDay()
+{
+ tipDatabase->deleteLater();
+ title->deleteLater();
+ tipTextContent->deleteLater();
+ imageLabel->deleteLater();
+ tipNumber->deleteLater();
+ showTipsOnStartupCheck->deleteLater();
+ content->deleteLater();
+ mainLayout->deleteLater();
+ buttonBox->deleteLater();
+ nextButton->deleteLater();
+ previousButton->deleteLater();
+ buttonBar->deleteLater();
+ delete image;
+}
+
+void DlgTipOfTheDay::nextClicked()
+{
+ emit newTipRequested(currentTip + 1);
+}
+
+void DlgTipOfTheDay::previousClicked()
+{
+ emit newTipRequested(currentTip - 1);
+}
+
+void DlgTipOfTheDay::updateTip(int tipId)
+{
+ QString titleText, contentText, imagePath;
+
+ if (tipId < 0) {
+ tipId = tipDatabase->rowCount() - 1;
+ } else if (tipId >= tipDatabase->rowCount()) {
+ tipId = tipId % tipDatabase->rowCount();
+ }
+
+ TipOfTheDay tip = tipDatabase->getTip(tipId);
+ titleText = tip.getTitle();
+ contentText = tip.getContent();
+ imagePath = tip.getImagePath();
+
+ title->setText("" + titleText + "
");
+ tipTextContent->setText(contentText);
+
+ if (!image->load(imagePath)) {
+ qDebug() << "Image failed to load from" << imagePath;
+ imageLabel->clear();
+ } else {
+ int h = std::min(std::max(image->height(), MIN_TIP_IMAGE_HEIGHT), MAX_TIP_IMAGE_HEIGHT);
+ int w = std::min(std::max(imageLabel->width(), MIN_TIP_IMAGE_WIDTH), MAX_TIP_IMAGE_WIDTH);
+ imageLabel->setPixmap(image->scaled(h, w, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+ }
+
+ date->setText("Tip added on: " + tip.getDate().toString("yyyy.MM.dd") + "");
+
+ tipNumber->setText("Tip " + QString::number(tipId + 1) + " / " + QString::number(tipDatabase->rowCount()));
+
+ currentTip = static_cast(tipId);
+ settingsCache->setLastShownTip(currentTip);
+}
+
+void DlgTipOfTheDay::resizeEvent(QResizeEvent *event)
+{
+ int h = imageLabel->height();
+ int w = imageLabel->width();
+ imageLabel->setPixmap(image->scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
+
+ QWidget::resizeEvent(event);
+}
diff --git a/cockatrice/src/dlg_tip_of_the_day.h b/cockatrice/src/dlg_tip_of_the_day.h
new file mode 100644
index 00000000..b40aab3b
--- /dev/null
+++ b/cockatrice/src/dlg_tip_of_the_day.h
@@ -0,0 +1,48 @@
+#ifndef DLG_TIPOFDAY_H
+#define DLG_TIPOFDAY_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class QLabel;
+class QPushButton;
+class QCheckBox;
+class TipsOfTheDay;
+
+class DlgTipOfTheDay : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit DlgTipOfTheDay(QWidget *parent = nullptr);
+ ~DlgTipOfTheDay() override;
+ bool successfulInit;
+signals:
+ void newTipRequested(int tipId);
+
+protected:
+ void resizeEvent(QResizeEvent *event) override;
+
+private:
+ unsigned int currentTip;
+ TipsOfTheDay *tipDatabase;
+ QLabel *title, *tipTextContent, *imageLabel, *tipNumber, *date;
+ QCheckBox *showTipsOnStartupCheck;
+ QPixmap *image;
+
+ QVBoxLayout *content, *mainLayout;
+ QDialogButtonBox *buttonBox;
+ QPushButton *nextButton, *previousButton;
+ QHBoxLayout *buttonBar;
+
+private slots:
+ void nextClicked();
+ void previousClicked();
+ void updateTip(int tipId);
+};
+
+#endif
diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp
index 3d1dc0c0..83ed6cb2 100644
--- a/cockatrice/src/main.cpp
+++ b/cockatrice/src/main.cpp
@@ -22,6 +22,7 @@
#include "QtNetwork/QNetworkInterface"
#include "carddatabase.h"
#include "dlg_settings.h"
+#include "dlg_tip_of_the_day.h"
#include "featureset.h"
#include "logger.h"
#include "pixmapgenerator.h"
@@ -137,6 +138,11 @@ int main(int argc, char *argv[])
ui.show();
qDebug("main(): ui.show() finished");
+ DlgTipOfTheDay tip;
+ if (settingsCache->getShowTipsOnStartup() && tip.successfulInit) {
+ tip.show();
+ }
+
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
app.exec();
diff --git a/cockatrice/src/setsmodel.cpp b/cockatrice/src/setsmodel.cpp
index e77790c5..1ae6a376 100644
--- a/cockatrice/src/setsmodel.cpp
+++ b/cockatrice/src/setsmodel.cpp
@@ -220,8 +220,8 @@ void SetsModel::sort(int column, Qt::SortOrder order)
void SetsModel::save(CardDatabase *db)
{
// order
- for (unsigned int i = 0; i < sets.size(); i++)
- sets[i]->setSortKey(i + 1);
+ for (int i = 0; i < sets.size(); i++)
+ sets[i]->setSortKey(static_cast(i + 1));
// enabled sets
for (const CardSetPtr &set : sets)
diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp
index 65fc3a53..c65bc888 100644
--- a/cockatrice/src/settingscache.cpp
+++ b/cockatrice/src/settingscache.cpp
@@ -179,6 +179,10 @@ SettingsCache::SettingsCache()
lang = settings->value("personal/lang").toString();
keepalive = settings->value("personal/keepalive", 5).toInt();
+ // tip of the day settings
+ showTipsOnStartup = settings->value("tipOfDay/showTips", true).toBool();
+ lastShownTip = settings->value("tipOfDay/lastShown", -1).toInt();
+
deckPath = getSafeConfigPath("paths/decks", dataPath + "/decks/");
replaysPath = getSafeConfigPath("paths/replays", dataPath + "/replays/");
picsPath = getSafeConfigPath("paths/pics", dataPath + "/pics/");
@@ -335,6 +339,18 @@ void SettingsCache::setLang(const QString &_lang)
emit langChanged();
}
+void SettingsCache::setShowTipsOnStartup(bool _showTipsOnStartup)
+{
+ showTipsOnStartup = _showTipsOnStartup;
+ settings->setValue("tipOfDay/showTips", showTipsOnStartup);
+}
+
+void SettingsCache::setLastShownTip(int _lastShownTip)
+{
+ lastShownTip = _lastShownTip;
+ settings->setValue("tipOfDay/lastShown", lastShownTip);
+}
+
void SettingsCache::setDeckPath(const QString &_deckPath)
{
deckPath = _deckPath;
diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h
index 2c931b40..482e5ef3 100644
--- a/cockatrice/src/settingscache.h
+++ b/cockatrice/src/settingscache.h
@@ -67,6 +67,8 @@ private:
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath,
spoilerDatabasePath, tokenDatabasePath, themeName;
bool notifyAboutUpdates;
+ bool showTipsOnStartup;
+ unsigned int lastShownTip;
bool mbDownloadSpoilers;
int updateReleaseChannel;
int maxFontSize;
@@ -199,6 +201,14 @@ public:
{
return notifyAboutUpdates;
}
+ bool getShowTipsOnStartup() const
+ {
+ return showTipsOnStartup;
+ }
+ unsigned int getLastShownTip() const
+ {
+ return lastShownTip;
+ }
ReleaseChannel *getUpdateReleaseChannel() const
{
return releaseChannels.at(updateReleaseChannel);
@@ -433,6 +443,8 @@ public slots:
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setTokenDialogGeometry(const QByteArray &_tokenDialog);
void setLang(const QString &_lang);
+ void setShowTipsOnStartup(bool _showTipsOnStartup);
+ void setLastShownTip(int _lastShowTip);
void setDeckPath(const QString &_deckPath);
void setReplaysPath(const QString &_replaysPath);
void setPicsPath(const QString &_picsPath);
diff --git a/cockatrice/src/tip_of_the_day.cpp b/cockatrice/src/tip_of_the_day.cpp
new file mode 100644
index 00000000..7c703679
--- /dev/null
+++ b/cockatrice/src/tip_of_the_day.cpp
@@ -0,0 +1,99 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "tip_of_the_day.h"
+
+#define TIPDDBMODEL_COLUMNS 3
+
+TipOfTheDay::TipOfTheDay(QString _title, QString _content, QString _imagePath, QDate _date)
+ : title(std::move(_title)), content(std::move(_content)), imagePath(std::move(_imagePath)), date(_date)
+{
+}
+
+TipsOfTheDay::TipsOfTheDay(QString xmlPath, QObject *parent) : QAbstractListModel(parent)
+{
+ tipList = new QList;
+
+ QFile xmlFile(xmlPath);
+
+ QTextStream errorStream(stderr);
+ if (!QFile::exists(xmlPath)) {
+ errorStream << tr("File does not exist.\n");
+ return;
+ } else if (!xmlFile.open(QIODevice::ReadOnly)) {
+ errorStream << tr("Failed to open file.\n");
+ return;
+ }
+
+ QXmlStreamReader reader(&xmlFile);
+
+ while (!reader.atEnd()) {
+ if (reader.readNext() == QXmlStreamReader::EndElement) {
+ break;
+ }
+
+ if (reader.name() == "tip") {
+ QString title, content, imagePath;
+ QDate date;
+ reader.readNext();
+ while (!reader.atEnd()) {
+ if (reader.readNext() == QXmlStreamReader::EndElement) {
+ break;
+ }
+
+ if (reader.name() == "title") {
+ title = reader.readElementText();
+ } else if (reader.name() == "text") {
+ content = reader.readElementText();
+ } else if (reader.name() == "image") {
+ imagePath = "theme:tips/images/" + reader.readElementText();
+ } else if (reader.name() == "date") {
+ date = QDate::fromString(reader.readElementText(), Qt::ISODate);
+ } else {
+ // unkown element, do nothing
+ }
+ }
+ tipList->append(TipOfTheDay(title, content, imagePath, date));
+ }
+ }
+}
+
+TipsOfTheDay::~TipsOfTheDay()
+{
+ delete tipList;
+}
+
+QVariant TipsOfTheDay::data(const QModelIndex &index, int /*role*/) const
+{
+ if (!index.isValid() || index.row() >= tipList->size() || index.column() >= TIPDDBMODEL_COLUMNS)
+ return QVariant();
+
+ TipOfTheDay tip = tipList->at(index.row());
+ switch (index.column()) {
+ case TitleColumn:
+ return tip.getTitle();
+ case ContentColumn:
+ return tip.getContent();
+ case ImagePathColumn:
+ return tip.getImagePath();
+ case DateColumn:
+ return tip.getDate();
+ default:
+ return QVariant();
+ }
+}
+
+TipOfTheDay TipsOfTheDay::getTip(int tipId)
+{
+ return tipList->at(tipId);
+}
+
+int TipsOfTheDay::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return tipList->size();
+}
diff --git a/cockatrice/src/tip_of_the_day.h b/cockatrice/src/tip_of_the_day.h
new file mode 100644
index 00000000..eb91852d
--- /dev/null
+++ b/cockatrice/src/tip_of_the_day.h
@@ -0,0 +1,54 @@
+#ifndef TIP_OF_DAY_H
+#define TIP_OF_DAY_H
+
+#include
+
+class TipOfTheDay
+{
+public:
+ explicit TipOfTheDay(QString _title, QString _content, QString _imagePath, QDate _date);
+ QString getTitle() const
+ {
+ return title;
+ }
+ QString getContent() const
+ {
+ return content;
+ }
+ QString getImagePath() const
+ {
+ return imagePath;
+ }
+ QDate getDate() const
+ {
+ return date;
+ }
+
+private:
+ QString title, content, imagePath;
+ QDate date;
+};
+
+class TipsOfTheDay : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum Columns
+ {
+ TitleColumn,
+ ContentColumn,
+ ImagePathColumn,
+ DateColumn,
+ };
+
+ explicit TipsOfTheDay(QString xmlPath, QObject *parent = nullptr);
+ ~TipsOfTheDay() override;
+ TipOfTheDay getTip(int tipId);
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+private:
+ QList *tipList;
+};
+
+#endif