[Move refactor] Move dialogs to interface/widgets/ (#6234)

* Move dialogs/ underneath interface/widgets since QDialog inherits from QWidget.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2025-10-09 15:25:18 +02:00 committed by GitHub
parent b8983f27ab
commit 474c1d0d89
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
66 changed files with 60 additions and 60 deletions

View file

@ -0,0 +1,377 @@
#include "dlg_connect.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QEvent>
#include <QGridLayout>
#include <QGroupBox>
#include <QKeyEvent>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
{
previousHostButton = new QRadioButton(tr("Known Hosts"), this);
previousHosts = new QComboBox(this);
btnDeleteServer = new QPushButton(this);
btnDeleteServer->setIcon(QPixmap("theme:icons/remove_row"));
btnDeleteServer->setToolTip(tr("Delete the currently selected saved server"));
btnDeleteServer->setFixedWidth(30);
connect(btnDeleteServer, &QPushButton::clicked, this, &DlgConnect::actRemoveSavedServer);
hps = new HandlePublicServers(this);
btnRefreshServers = new QPushButton(this);
btnRefreshServers->setIcon(QPixmap("theme:icons/sync"));
btnRefreshServers->setToolTip(tr("Refresh the server list with known public servers"));
btnRefreshServers->setFixedWidth(30);
connect(hps, &HandlePublicServers::sigPublicServersDownloadedSuccessfully, this, [this] { rebuildComboBoxList(); });
connect(hps, &HandlePublicServers::sigPublicServersDownloadedUnsuccessfully, this,
&DlgConnect::rebuildComboBoxList);
connect(btnRefreshServers, &QPushButton::released, this, &DlgConnect::downloadThePublicServers);
connect(this, &DlgConnect::sigPublicServersDownloaded, this, [this] { rebuildComboBoxList(); });
preRebuildComboBoxList();
newHostButton = new QRadioButton(tr("New Host"), this);
saveLabel = new QLabel(tr("Name:"));
saveEdit = new QLineEdit;
saveEdit->setMaxLength(MAX_NAME_LENGTH);
saveLabel->setBuddy(saveEdit);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit;
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit;
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit;
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
passwordLabel = new QLabel(tr("P&assword:"));
passwordEdit = new QLineEdit;
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
passwordEdit->setEchoMode(QLineEdit::Password);
savePasswordCheckBox = new QCheckBox(tr("&Save password"));
autoConnectCheckBox = new QCheckBox(tr("A&uto connect"));
autoConnectCheckBox->setToolTip(tr("Automatically connect to the most recent login when Cockatrice opens"));
auto &servers = SettingsCache::instance().servers();
if (servers.getSavePassword()) {
autoConnectCheckBox->setChecked(servers.getAutoConnect() > 0);
autoConnectCheckBox->setEnabled(true);
} else {
servers.setAutoConnect(0);
autoConnectCheckBox->setChecked(false);
autoConnectCheckBox->setEnabled(false);
}
connect(savePasswordCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &DlgConnect::passwordSaved);
connect(autoConnectCheckBox, &QCheckBox::QT_STATE_CHANGED, &servers, &ServersSettings::setAutoConnect);
serverIssuesLabel =
new QLabel(tr("If you have any trouble connecting or registering then contact the server staff for help!"));
serverIssuesLabel->setWordWrap(true);
serverContactLabel = new QLabel(tr("Webpage") + ":");
serverContactLink = new QLabel;
serverContactLink->setTextFormat(Qt::RichText);
serverContactLink->setTextInteractionFlags(Qt::TextBrowserInteraction);
serverContactLink->setOpenExternalLinks(true);
updateDisplayInfo(previousHosts->currentText());
btnForgotPassword = new QPushButton(this);
btnForgotPassword->setIcon(QPixmap("theme:icons/forgot_password"));
btnForgotPassword->setToolTip(tr("Reset Password"));
btnForgotPassword->setFixedWidth(30);
connect(btnForgotPassword, &QPushButton::released, this, &DlgConnect::actForgotPassword);
forgotPasswordLabel = new QLabel(tr("Forgot password?"));
forgotPasswordLabel->setBuddy(btnForgotPassword);
btnConnect = new QPushButton(tr("&Connect"));
connect(btnConnect, &QPushButton::released, this, &DlgConnect::actOk);
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel);
buttonBox->addButton(btnConnect, QDialogButtonBox::AcceptRole);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgConnect::reject);
newHolderLayout = new QHBoxLayout;
newHolderLayout->addWidget(previousHosts);
newHolderLayout->addWidget(btnDeleteServer);
newHolderLayout->addWidget(btnRefreshServers);
connectionLayout = new QGridLayout;
connectionLayout->addWidget(previousHostButton, 0, 1);
connectionLayout->addLayout(newHolderLayout, 1, 1, 1, 2);
connectionLayout->addWidget(newHostButton, 2, 1);
connectionLayout->addWidget(saveLabel, 3, 0);
connectionLayout->addWidget(saveEdit, 3, 1);
connectionLayout->addWidget(hostLabel, 4, 0);
connectionLayout->addWidget(hostEdit, 4, 1);
connectionLayout->addWidget(portLabel, 5, 0);
connectionLayout->addWidget(portEdit, 5, 1);
connectionLayout->addWidget(autoConnectCheckBox, 6, 1);
restrictionsGroupBox = new QGroupBox(tr("Server"));
restrictionsGroupBox->setLayout(connectionLayout);
serverInfoLayout = new QGridLayout;
serverInfoLayout->addWidget(serverIssuesLabel, 0, 0, 1, 4, Qt::AlignTop);
serverInfoLayout->addWidget(serverContactLabel, 1, 0);
serverInfoLayout->addWidget(serverContactLink, 1, 1, 1, 3);
forgotPasswordLayout = new QHBoxLayout;
forgotPasswordLayout->addWidget(forgotPasswordLabel, 0, Qt::AlignLeft);
forgotPasswordLayout->addWidget(btnForgotPassword, 0, Qt::AlignLeft);
loginLayout = new QGridLayout;
loginLayout->addWidget(playernameLabel, 0, 0);
loginLayout->addWidget(playernameEdit, 0, 1, 1, 2);
loginLayout->addWidget(passwordLabel, 1, 0);
loginLayout->addWidget(passwordEdit, 1, 1, 1, 2);
loginLayout->addWidget(savePasswordCheckBox, 2, 1);
loginLayout->addLayout(forgotPasswordLayout, 3, 1);
loginGroupBox = new QGroupBox(tr("Login"));
loginGroupBox->setLayout(loginLayout);
serverInfoGroupBox = new QGroupBox(tr("Server Contact"));
serverInfoGroupBox->setLayout(serverInfoLayout);
grid = new QGridLayout;
grid->addWidget(restrictionsGroupBox, 0, 0);
grid->addWidget(serverInfoGroupBox, 1, 0);
grid->addWidget(loginGroupBox, 2, 0);
mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Connect to Server"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
connect(previousHostButton, &QRadioButton::toggled, this, &DlgConnect::previousHostSelected);
connect(newHostButton, &QRadioButton::toggled, this, &DlgConnect::newHostSelected);
previousHostButton->setChecked(true);
connect(previousHosts, &QComboBox::currentTextChanged, this, &DlgConnect::updateDisplayInfo);
playernameEdit->setFocus();
}
DlgConnect::~DlgConnect() = default;
void DlgConnect::downloadThePublicServers()
{
btnRefreshServers->setDisabled(true);
previousHosts->clear();
previousHosts->addItem(placeHolderText);
hps->downloadPublicServers();
}
void DlgConnect::preRebuildComboBoxList()
{
UserConnection_Information uci;
savedHostList = uci.getServerInfo();
if (savedHostList.size() == 1) {
downloadThePublicServers();
} else {
rebuildComboBoxList();
}
}
void DlgConnect::rebuildComboBoxList(int failure)
{
Q_UNUSED(failure);
previousHosts->clear();
UserConnection_Information uci;
savedHostList = uci.getServerInfo();
auto &servers = SettingsCache::instance().servers();
bool autoConnectEnabled = servers.getAutoConnect() > 0;
QString previousHostName = servers.getPrevioushostName();
QString autoConnectSaveName = servers.getSaveName();
int index = 0;
for (const auto &pair : savedHostList) {
const auto &tmp = pair.second;
QString saveName = tmp.getSaveName();
if (saveName.size()) {
previousHosts->addItem(saveName);
if (autoConnectEnabled) {
if (saveName.compare(autoConnectSaveName) == 0) {
previousHosts->setCurrentIndex(index);
}
} else if (saveName.compare(previousHostName) == 0) {
previousHosts->setCurrentIndex(index);
}
++index;
}
}
// Re-enable the refresh server button
btnRefreshServers->setDisabled(false);
}
void DlgConnect::previousHostSelected(bool state)
{
if (state) {
saveEdit->setDisabled(true);
hostEdit->setDisabled(true);
portEdit->setDisabled(true);
previousHosts->setDisabled(false);
btnRefreshServers->setDisabled(false);
}
}
void DlgConnect::updateDisplayInfo(const QString &saveName)
{
if (saveEdit == nullptr || saveName == placeHolderText) {
return;
}
UserConnection_Information uci;
QStringList _data = uci.getServerInfo(saveName);
if (_data.isEmpty()) {
_data << ""
<< ""
<< ""
<< ""
<< ""
<< ""
<< "";
}
bool savePasswordStatus = (_data.at(5) == "1");
saveEdit->setText(_data.at(0));
hostEdit->setText(_data.at(1));
portEdit->setText(_data.at(2));
playernameEdit->setText(_data.at(3));
savePasswordCheckBox->setChecked(savePasswordStatus);
if (savePasswordStatus) {
passwordEdit->setText(_data.at(4));
}
if (!_data.at(6).isEmpty()) {
QString formattedLink = "<a href=\"" + _data.at(6) + "\">" + _data.at(6) + "</a>";
serverContactLabel->setText(tr("Webpage") + ":");
serverContactLink->setText(formattedLink);
} else {
serverContactLabel->setText("");
serverContactLink->setText("");
}
}
void DlgConnect::newHostSelected(bool state)
{
if (state) {
previousHosts->setDisabled(true);
btnRefreshServers->setDisabled(true);
hostEdit->clear();
hostEdit->setPlaceholderText(tr("Server URL"));
hostEdit->setDisabled(false);
portEdit->clear();
portEdit->setPlaceholderText(tr("Communication Port"));
portEdit->setDisabled(false);
playernameEdit->clear();
passwordEdit->clear();
saveEdit->clear();
saveEdit->setPlaceholderText(tr("Unique Server Name"));
saveEdit->setDisabled(false);
serverContactLabel->setText("");
serverContactLink->setText("");
} else {
preRebuildComboBoxList();
}
}
void DlgConnect::passwordSaved(QT_STATE_CHANGED_T state)
{
Q_UNUSED(state);
if (savePasswordCheckBox->isChecked()) {
autoConnectCheckBox->setEnabled(true);
} else {
autoConnectCheckBox->setChecked(false);
autoConnectCheckBox->setEnabled(false);
}
}
void DlgConnect::actOk()
{
ServersSettings &servers = SettingsCache::instance().servers();
if (newHostButton->isChecked()) {
if (saveEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Connection Warning"), tr("You need to name your new connection profile."));
return;
}
servers.addNewServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(), portEdit->text().trimmed(),
playernameEdit->text().trimmed(), passwordEdit->text(), savePasswordCheckBox->isChecked());
} else {
servers.updateExistingServer(saveEdit->text().trimmed(), hostEdit->text().trimmed(), portEdit->text().trimmed(),
playernameEdit->text().trimmed(), passwordEdit->text(),
savePasswordCheckBox->isChecked());
}
servers.setPrevioushostName(saveEdit->text());
if (playernameEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Connect Warning"), tr("The player name can't be empty."));
return;
}
accept();
}
QString DlgConnect::getHost() const
{
return hostEdit->text().trimmed();
}
void DlgConnect::actForgotPassword()
{
ServersSettings &servers = SettingsCache::instance().servers();
servers.setFPHostName(hostEdit->text());
servers.setFPPort(portEdit->text());
servers.setFPPlayerName(playernameEdit->text().trimmed());
emit sigStartForgotPasswordRequest();
}
void DlgConnect::actRemoveSavedServer()
{
SettingsCache::instance().servers().removeServer(hostEdit->text());
previousHosts->removeItem(previousHosts->currentIndex());
}

View file

@ -0,0 +1,82 @@
/**
* @file dlg_connect.h
* @ingroup ConnectionDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_CONNECT_H
#define DLG_CONNECT_H
#include "../interface/widgets/server/handle_public_servers.h"
#include "../interface/widgets/server/user/user_info_connection.h"
#include <QDialog>
#include <QLineEdit>
#include <libcockatrice/utility/macros.h>
class QCheckBox;
class QComboBox;
class QGridLayout;
class QGroupBox;
class QHBoxLayout;
class QLabel;
class QPushButton;
class QRadioButton;
class QVBoxLayout;
class DlgConnect : public QDialog
{
Q_OBJECT
signals:
void sigStartForgotPasswordRequest();
void sigPublicServersDownloaded();
public:
explicit DlgConnect(QWidget *parent = nullptr);
~DlgConnect() override;
QString getHost() const;
int getPort() const
{
return portEdit->text().toInt();
}
QString getPlayerName() const
{
return playernameEdit->text();
}
QString getPassword() const
{
return passwordEdit->text();
}
public slots:
void downloadThePublicServers();
private slots:
void actOk();
void passwordSaved(QT_STATE_CHANGED_T state);
void previousHostSelected(bool state);
void newHostSelected(bool state);
void actForgotPassword();
void actRemoveSavedServer();
void updateDisplayInfo(const QString &saveName);
void preRebuildComboBoxList();
void rebuildComboBoxList(int failure = -1);
private:
QGridLayout *connectionLayout, *loginLayout, *serverInfoLayout, *grid;
QHBoxLayout *newHolderLayout, *forgotPasswordLayout;
QGroupBox *loginGroupBox, *serverInfoGroupBox, *restrictionsGroupBox;
QVBoxLayout *mainLayout;
QLabel *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *saveLabel, *serverIssuesLabel,
*serverContactLabel, *serverContactLink, *forgotPasswordLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *saveEdit;
QCheckBox *savePasswordCheckBox, *autoConnectCheckBox;
QComboBox *previousHosts;
QRadioButton *newHostButton, *previousHostButton;
QPushButton *btnConnect, *btnForgotPassword, *btnRefreshServers, *btnDeleteServer;
QMap<QString, std::pair<QString, UserConnection_Information>> savedHostList;
HandlePublicServers *hps;
const QString placeHolderText = tr("Downloading...");
};
#endif

View file

@ -0,0 +1,40 @@
#include "dlg_convert_deck_to_cod_format.h"
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QLabel>
#include <QVBoxLayout>
DialogConvertDeckToCodFormat::DialogConvertDeckToCodFormat(QWidget *parent) : QDialog(parent)
{
layout = new QVBoxLayout(this);
label = new QLabel();
layout->addWidget(label);
dontAskAgainCheckbox = new QCheckBox(this);
layout->addWidget(dontAskAgainCheckbox);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::accepted, this, [this]() { accept(); });
connect(buttonBox, &QDialogButtonBox::rejected, this, [this]() { reject(); });
setLayout(layout);
retranslateUi();
}
void DialogConvertDeckToCodFormat::retranslateUi()
{
setWindowTitle(tr("Deck Format Conversion"));
label->setText(
tr("You tried to add a tag to a .txt format deck.\n Tags can only be added to .cod format decks.\n Do "
"you want to convert the deck to the .cod format?"));
dontAskAgainCheckbox->setText(tr("Remember and automatically apply choice in the future"));
}
bool DialogConvertDeckToCodFormat::dontAskAgain() const
{
return dontAskAgainCheckbox->isChecked();
}

View file

@ -0,0 +1,36 @@
/**
* @file dlg_convert_deck_to_cod_format.h
* @ingroup LocalDeckStorageDialogs
* @ingroup Lobby
* @brief TODO: Document this.
*/
#ifndef DIALOG_CONVERT_DECK_TO_COD_FORMAT_H
#define DIALOG_CONVERT_DECK_TO_COD_FORMAT_H
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QVBoxLayout>
class DialogConvertDeckToCodFormat : public QDialog
{
Q_OBJECT
public:
explicit DialogConvertDeckToCodFormat(QWidget *parent);
void retranslateUi();
bool dontAskAgain() const;
private:
QVBoxLayout *layout;
QLabel *label;
QCheckBox *dontAskAgainCheckbox;
QDialogButtonBox *buttonBox;
Q_DISABLE_COPY(DialogConvertDeckToCodFormat)
};
#endif // DIALOG_CONVERT_DECK_TO_COD_FORMAT_H

View file

@ -0,0 +1,327 @@
#include "dlg_create_game.h"
#include "../interface/widgets/tabs/tab_room.h"
#include <QApplication>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QSet>
#include <QSpinBox>
#include <QWizard>
#include <libcockatrice/protocol/pb/serverinfo_game.pb.h>
#include <libcockatrice/protocol/pending_command.h>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
void DlgCreateGame::sharedCtor()
{
rememberGameSettings = new QCheckBox(tr("Re&member settings"));
descriptionLabel = new QLabel(tr("&Description:"));
descriptionEdit = new QLineEdit;
descriptionEdit->setMaxLength(MAX_NAME_LENGTH);
descriptionLabel->setBuddy(descriptionEdit);
maxPlayersLabel = new QLabel(tr("P&layers:"));
maxPlayersEdit = new QSpinBox();
maxPlayersEdit->setMinimum(1);
maxPlayersEdit->setMaximum(100);
maxPlayersEdit->setValue(2);
maxPlayersLabel->setBuddy(maxPlayersEdit);
QGridLayout *generalGrid = new QGridLayout;
generalGrid->addWidget(descriptionLabel, 0, 0);
generalGrid->addWidget(descriptionEdit, 0, 1);
generalGrid->addWidget(maxPlayersLabel, 1, 0);
generalGrid->addWidget(maxPlayersEdit, 1, 1);
generalGroupBox = new QGroupBox(tr("General"));
generalGroupBox->setLayout(generalGrid);
QVBoxLayout *gameTypeLayout = new QVBoxLayout;
QMapIterator<int, QString> gameTypeIterator(gameTypes);
while (gameTypeIterator.hasNext()) {
gameTypeIterator.next();
QRadioButton *gameTypeRadioButton = new QRadioButton(gameTypeIterator.value(), this);
gameTypeLayout->addWidget(gameTypeRadioButton);
gameTypeCheckBoxes.insert(gameTypeIterator.key(), gameTypeRadioButton);
bool isChecked = SettingsCache::instance().getGameTypes().contains(gameTypeIterator.value() + ", ");
gameTypeCheckBoxes[gameTypeIterator.key()]->setChecked(isChecked);
}
QGroupBox *gameTypeGroupBox = new QGroupBox(tr("Game type"));
gameTypeGroupBox->setLayout(gameTypeLayout);
passwordLabel = new QLabel(tr("&Password:"));
passwordEdit = new QLineEdit;
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
onlyBuddiesCheckBox = new QCheckBox(tr("Only &buddies can join"));
onlyRegisteredCheckBox = new QCheckBox(tr("Only &registered users can join"));
if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsRegistered) {
onlyRegisteredCheckBox->setChecked(true);
} else {
onlyBuddiesCheckBox->setEnabled(false);
onlyRegisteredCheckBox->setEnabled(false);
}
QGridLayout *joinRestrictionsLayout = new QGridLayout;
joinRestrictionsLayout->addWidget(passwordLabel, 0, 0);
joinRestrictionsLayout->addWidget(passwordEdit, 0, 1);
joinRestrictionsLayout->addWidget(onlyBuddiesCheckBox, 1, 0, 1, 2);
joinRestrictionsLayout->addWidget(onlyRegisteredCheckBox, 2, 0, 1, 2);
QGroupBox *joinRestrictionsGroupBox = new QGroupBox(tr("Joining restrictions"));
joinRestrictionsGroupBox->setLayout(joinRestrictionsLayout);
spectatorsAllowedCheckBox = new QCheckBox(tr("&Spectators can watch"));
spectatorsAllowedCheckBox->setChecked(true);
connect(spectatorsAllowedCheckBox, &QCheckBox::QT_STATE_CHANGED, this, &DlgCreateGame::spectatorsAllowedChanged);
spectatorsNeedPasswordCheckBox = new QCheckBox(tr("Spectators &need a password to watch"));
spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat"));
spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands"));
createGameAsSpectatorCheckBox = new QCheckBox(tr("Create game as spectator"));
QVBoxLayout *spectatorsLayout = new QVBoxLayout;
spectatorsLayout->addWidget(spectatorsAllowedCheckBox);
spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox);
spectatorsLayout->addWidget(spectatorsCanTalkCheckBox);
spectatorsLayout->addWidget(spectatorsSeeEverythingCheckBox);
spectatorsLayout->addWidget(createGameAsSpectatorCheckBox);
spectatorsGroupBox = new QGroupBox(tr("Spectators"));
spectatorsGroupBox->setLayout(spectatorsLayout);
startingLifeTotalLabel = new QLabel(tr("Starting life total:"));
startingLifeTotalEdit = new QSpinBox();
startingLifeTotalEdit->setMinimum(1);
startingLifeTotalEdit->setMaximum(99999); ///< Arbitrary but we can raise this when people start complaining.
startingLifeTotalEdit->setValue(20);
startingLifeTotalLabel->setBuddy(startingLifeTotalEdit);
shareDecklistsOnLoadLabel = new QLabel(tr("Open decklists in lobby"));
shareDecklistsOnLoadCheckBox = new QCheckBox();
shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox);
QGridLayout *gameSetupOptionsLayout = new QGridLayout;
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0);
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 1);
gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options"));
gameSetupOptionsGroupBox->setLayout(gameSetupOptionsLayout);
auto *grid = new QGridLayout;
// Top row
grid->addWidget(generalGroupBox, 0, 0);
grid->addWidget(joinRestrictionsGroupBox, 0, 1);
// Middle row: left column
grid->addWidget(gameTypeGroupBox, 1, 0);
// Middle row: right column (game setup + spectators)
auto *rightLayout = new QVBoxLayout;
rightLayout->addWidget(spectatorsGroupBox, Qt::AlignTop); // top
rightLayout->addWidget(gameSetupOptionsGroupBox); // bottom
grid->addLayout(rightLayout, 1, 1);
// Bottom row
grid->addWidget(rememberGameSettings, 3, 0, 1, 2); // span both columns if needed
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgCreateGame::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setFixedHeight(sizeHint().height());
}
DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameTypes, QWidget *parent)
: QDialog(parent), room(_room), gameTypes(_gameTypes)
{
sharedCtor();
rememberGameSettings->setChecked(SettingsCache::instance().getRememberGameSettings());
descriptionEdit->setText(SettingsCache::instance().getGameDescription());
maxPlayersEdit->setValue(SettingsCache::instance().getMaxPlayers());
if (room && room->getUserInfo()->user_level() & ServerInfo_User::IsRegistered) {
onlyBuddiesCheckBox->setChecked(SettingsCache::instance().getOnlyBuddies());
onlyRegisteredCheckBox->setChecked(SettingsCache::instance().getOnlyRegistered());
} else {
onlyBuddiesCheckBox->setEnabled(false);
onlyRegisteredCheckBox->setEnabled(false);
}
spectatorsAllowedCheckBox->setChecked(SettingsCache::instance().getSpectatorsAllowed());
spectatorsNeedPasswordCheckBox->setChecked(SettingsCache::instance().getSpectatorsNeedPassword());
spectatorsCanTalkCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanTalk());
spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything());
createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator());
startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal());
shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().getShareDecklistsOnLoad());
if (!rememberGameSettings->isChecked()) {
actReset();
}
descriptionEdit->setFocus();
clearButton = new QPushButton(tr("&Clear"));
buttonBox->addButton(QDialogButtonBox::Cancel);
buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgCreateGame::actOK);
connect(clearButton, &QPushButton::clicked, this, &DlgCreateGame::actReset);
setWindowTitle(tr("Create game"));
}
DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMap<int, QString> &_gameTypes, QWidget *parent)
: QDialog(parent), room(0), gameTypes(_gameTypes)
{
sharedCtor();
rememberGameSettings->setEnabled(false);
descriptionEdit->setEnabled(false);
maxPlayersEdit->setEnabled(false);
passwordEdit->setEnabled(false);
onlyBuddiesCheckBox->setEnabled(false);
onlyRegisteredCheckBox->setEnabled(false);
spectatorsAllowedCheckBox->setEnabled(false);
spectatorsNeedPasswordCheckBox->setEnabled(false);
spectatorsCanTalkCheckBox->setEnabled(false);
spectatorsSeeEverythingCheckBox->setEnabled(false);
createGameAsSpectatorCheckBox->setEnabled(false);
startingLifeTotalEdit->setEnabled(false);
shareDecklistsOnLoadCheckBox->setEnabled(false);
descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
maxPlayersEdit->setValue(gameInfo.max_players());
onlyBuddiesCheckBox->setChecked(gameInfo.only_buddies());
onlyRegisteredCheckBox->setChecked(gameInfo.only_registered());
spectatorsAllowedCheckBox->setChecked(gameInfo.spectators_allowed());
spectatorsNeedPasswordCheckBox->setChecked(gameInfo.spectators_need_password());
spectatorsCanTalkCheckBox->setChecked(gameInfo.spectators_can_chat());
spectatorsSeeEverythingCheckBox->setChecked(gameInfo.spectators_omniscient());
QSet<int> types;
for (int i = 0; i < gameInfo.game_types_size(); ++i)
types.insert(gameInfo.game_types(i));
QMapIterator<int, QString> gameTypeIterator(gameTypes);
while (gameTypeIterator.hasNext()) {
gameTypeIterator.next();
QRadioButton *gameTypeCheckBox = gameTypeCheckBoxes.value(gameTypeIterator.key());
gameTypeCheckBox->setEnabled(false);
gameTypeCheckBox->setChecked(types.contains(gameTypeIterator.key()));
}
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgCreateGame::accept);
setWindowTitle(tr("Game information"));
}
void DlgCreateGame::actReset()
{
descriptionEdit->setText("");
maxPlayersEdit->setValue(2);
passwordEdit->setText("");
onlyBuddiesCheckBox->setChecked(false);
onlyRegisteredCheckBox->setChecked(room && room->getUserInfo()->user_level() & ServerInfo_User::IsRegistered);
spectatorsAllowedCheckBox->setChecked(true);
spectatorsNeedPasswordCheckBox->setChecked(false);
spectatorsCanTalkCheckBox->setChecked(false);
spectatorsSeeEverythingCheckBox->setChecked(false);
createGameAsSpectatorCheckBox->setChecked(false);
startingLifeTotalEdit->setValue(20);
shareDecklistsOnLoadCheckBox->setChecked(false);
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
while (gameTypeCheckBoxIterator.hasNext()) {
gameTypeCheckBoxIterator.next();
// must set auto enclusive to false to be able to set the check to false
gameTypeCheckBoxIterator.value()->setAutoExclusive(false);
gameTypeCheckBoxIterator.value()->setChecked(false);
gameTypeCheckBoxIterator.value()->setAutoExclusive(true);
}
descriptionEdit->setFocus();
}
void DlgCreateGame::actOK()
{
Command_CreateGame cmd;
cmd.set_description(descriptionEdit->text().simplified().toStdString());
cmd.set_password(passwordEdit->text().toStdString());
cmd.set_max_players(maxPlayersEdit->value());
cmd.set_only_buddies(onlyBuddiesCheckBox->isChecked());
cmd.set_only_registered(onlyRegisteredCheckBox->isChecked());
cmd.set_spectators_allowed(spectatorsAllowedCheckBox->isChecked());
cmd.set_spectators_need_password(spectatorsNeedPasswordCheckBox->isChecked());
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
cmd.set_starting_life_total(startingLifeTotalEdit->value());
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
QString _gameTypes = QString();
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
while (gameTypeCheckBoxIterator.hasNext()) {
gameTypeCheckBoxIterator.next();
if (gameTypeCheckBoxIterator.value()->isChecked()) {
cmd.add_game_type_ids(gameTypeCheckBoxIterator.key());
_gameTypes += gameTypeCheckBoxIterator.value()->text() + ", ";
}
}
SettingsCache::instance().setRememberGameSettings(rememberGameSettings->isChecked());
if (rememberGameSettings->isChecked()) {
SettingsCache::instance().setGameDescription(descriptionEdit->text());
SettingsCache::instance().setMaxPlayers(maxPlayersEdit->value());
SettingsCache::instance().setOnlyBuddies(onlyBuddiesCheckBox->isChecked());
SettingsCache::instance().setOnlyRegistered(onlyRegisteredCheckBox->isChecked());
SettingsCache::instance().setSpectatorsAllowed(spectatorsAllowedCheckBox->isChecked());
SettingsCache::instance().setSpectatorsNeedPassword(spectatorsNeedPasswordCheckBox->isChecked());
SettingsCache::instance().setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value());
SettingsCache::instance().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked());
SettingsCache::instance().setGameTypes(_gameTypes);
}
PendingCommand *pend = room->prepareRoomCommand(cmd);
connect(pend, &PendingCommand::finished, this, &DlgCreateGame::checkResponse);
room->sendRoomCommand(pend);
buttonBox->setEnabled(false);
}
void DlgCreateGame::checkResponse(const Response &response)
{
buttonBox->setEnabled(true);
if (response.response_code() == Response::RespOk)
accept();
else {
QMessageBox::critical(this, tr("Error"), tr("Server error."));
return;
}
}
void DlgCreateGame::spectatorsAllowedChanged(QT_STATE_CHANGED_T state)
{
spectatorsNeedPasswordCheckBox->setEnabled(state);
spectatorsCanTalkCheckBox->setEnabled(state);
spectatorsSeeEverythingCheckBox->setEnabled(state);
}

View file

@ -0,0 +1,58 @@
/**
* @file dlg_create_game.h
* @ingroup RoomDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_CREATEGAME_H
#define DLG_CREATEGAME_H
#include <QDialog>
#include <QMap>
#include <libcockatrice/utility/macros.h>
class QCheckBox;
class QDialogButtonBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QRadioButton;
class QSpinBox;
class Response;
class ServerInfo_Game;
class TabRoom;
class DlgCreateGame : public QDialog
{
Q_OBJECT
public:
DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameTypes, QWidget *parent = nullptr);
DlgCreateGame(const ServerInfo_Game &game, const QMap<int, QString> &_gameTypes, QWidget *parent = nullptr);
private slots:
void actOK();
void actReset();
void checkResponse(const Response &response);
void spectatorsAllowedChanged(QT_STATE_CHANGED_T state);
private:
TabRoom *room;
QMap<int, QString> gameTypes;
QMap<int, QRadioButton *> gameTypeCheckBoxes;
QGroupBox *generalGroupBox, *spectatorsGroupBox, *gameSetupOptionsGroupBox;
QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel, *startingLifeTotalLabel, *shareDecklistsOnLoadLabel;
QLineEdit *descriptionEdit, *passwordEdit;
QSpinBox *maxPlayersEdit, *startingLifeTotalEdit;
QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox;
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
*spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox;
QCheckBox *shareDecklistsOnLoadCheckBox;
QDialogButtonBox *buttonBox;
QPushButton *clearButton;
QCheckBox *rememberGameSettings;
void sharedCtor();
};
#endif

View file

@ -0,0 +1,148 @@
#include "dlg_default_tags_editor.h"
#include <QMessageBox>
#include <QVBoxLayout>
#include <libcockatrice/settings/cache_settings.h>
DlgDefaultTagsEditor::DlgDefaultTagsEditor(QWidget *parent) : QDialog(parent)
{
mainLayout = new QVBoxLayout(this);
// Input field + Add button (horizontal layout)
inputLayout = new QHBoxLayout();
inputField = new QLineEdit(this);
addButton = new QPushButton(this);
inputLayout->addWidget(inputField);
inputLayout->addWidget(addButton);
mainLayout->addLayout(inputLayout);
// List widget for tags
listWidget = new QListWidget(this);
listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
listWidget->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
mainLayout->addWidget(listWidget);
// Button layout (Confirm and Cancel)
buttonLayout = new QHBoxLayout();
confirmButton = new QPushButton(this);
cancelButton = new QPushButton(this);
buttonLayout->addWidget(confirmButton);
buttonLayout->addWidget(cancelButton);
mainLayout->addLayout(buttonLayout);
loadStringList();
retranslateUi();
// Connect signals
connect(addButton, &QPushButton::clicked, this, &DlgDefaultTagsEditor::addItem);
connect(cancelButton, &QPushButton::clicked, this, &DlgDefaultTagsEditor::reject); // Cancel closes dialog
connect(confirmButton, &QPushButton::clicked, this, &DlgDefaultTagsEditor::confirmChanges);
connect(inputField, &QLineEdit::returnPressed, this, &DlgDefaultTagsEditor::addItem);
}
void DlgDefaultTagsEditor::retranslateUi()
{
setWindowTitle(tr("Edit Tags"));
addButton->setText(tr("Add"));
confirmButton->setText(tr("Confirm"));
cancelButton->setText(tr("Cancel"));
inputField->setPlaceholderText(tr("Enter a tag and press Enter"));
}
void DlgDefaultTagsEditor::loadStringList()
{
listWidget->clear();
QStringList tags = SettingsCache::instance().getVisualDeckStorageDefaultTagsList();
for (const QString &tag : tags) {
auto *item = new QListWidgetItem(); // Create item but don't insert yet
QWidget *widget = new QWidget(this);
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->setContentsMargins(2, 2, 2, 2);
layout->setSpacing(5);
QLineEdit *lineEdit = new QLineEdit(tag, this);
lineEdit->setFrame(false);
lineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
layout->addWidget(lineEdit);
QPushButton *deleteButton = new QPushButton(tr(""), this);
deleteButton->setFixedSize(25, 25);
layout->addWidget(deleteButton);
widget->setLayout(layout);
// Set item height explicitly to match the widget (widgets get squished without it)
item->setSizeHint(widget->sizeHint());
listWidget->addItem(item);
listWidget->setItemWidget(item, widget);
connect(deleteButton, &QPushButton::clicked, this, [this, item]() { deleteItem(item); });
}
}
void DlgDefaultTagsEditor::addItem()
{
QString newTag = inputField->text().trimmed();
if (newTag.isEmpty()) {
QMessageBox::warning(this, tr("Invalid Input"), tr("Tag name cannot be empty!"));
return;
}
// Prevent duplicate tags
for (int i = 0; i < listWidget->count(); ++i) {
QWidget *widget = listWidget->itemWidget(listWidget->item(i));
if (!widget)
continue;
QLineEdit *lineEdit = widget->findChild<QLineEdit *>();
if (lineEdit && lineEdit->text() == newTag) {
QMessageBox::warning(this, tr("Duplicate Tag"), tr("This tag already exists."));
return;
}
}
// Add new tag
auto *item = new QListWidgetItem(listWidget);
QWidget *widget = new QWidget(this);
QHBoxLayout *layout = new QHBoxLayout(widget);
layout->setContentsMargins(0, 0, 0, 0);
// Editable tag label
QLineEdit *lineEdit = new QLineEdit(newTag, this);
lineEdit->setFrame(false);
layout->addWidget(lineEdit);
// Delete button
QPushButton *deleteButton = new QPushButton(tr(""), this);
deleteButton->setFixedSize(24, 24);
layout->addWidget(deleteButton);
widget->setLayout(layout);
listWidget->setItemWidget(item, widget);
connect(deleteButton, &QPushButton::clicked, this, [this, item]() { deleteItem(item); });
inputField->clear();
}
void DlgDefaultTagsEditor::deleteItem(QListWidgetItem *item)
{
delete listWidget->takeItem(listWidget->row(item));
}
void DlgDefaultTagsEditor::confirmChanges()
{
QStringList updatedList;
for (int i = 0; i < listWidget->count(); ++i) {
QWidget *widget = listWidget->itemWidget(listWidget->item(i));
if (!widget)
continue;
QLineEdit *lineEdit = widget->findChild<QLineEdit *>();
if (lineEdit) {
updatedList.append(lineEdit->text());
}
}
SettingsCache::instance().setVisualDeckStorageDefaultTagsList(updatedList);
accept(); // Close dialog and confirm changes
}

View file

@ -0,0 +1,43 @@
/**
* @file dlg_default_tags_editor.h
* @ingroup Dialogs
* @ingroup DeckStorageWidgets
* @brief TODO: Document this.
*/
#ifndef DLG_DEFAULT_TAGS_EDITOR_H
#define DLG_DEFAULT_TAGS_EDITOR_H
#include <QDialog>
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QVBoxLayout>
class DlgDefaultTagsEditor : public QDialog
{
Q_OBJECT
public:
explicit DlgDefaultTagsEditor(QWidget *parent = nullptr);
private slots:
void addItem();
void deleteItem(QListWidgetItem *item);
void confirmChanges();
private:
QVBoxLayout *mainLayout;
QHBoxLayout *inputLayout;
QListWidget *listWidget;
QHBoxLayout *buttonLayout;
QLineEdit *inputField;
QPushButton *addButton;
QPushButton *confirmButton;
QPushButton *cancelButton;
void loadStringList();
void retranslateUi();
};
#endif // DLG_DEFAULT_TAGS_EDITOR_H

View file

@ -0,0 +1,87 @@
#include "dlg_edit_avatar.h"
#include <QBuffer>
#include <QDebug>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QImageReader>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <libcockatrice/utility/trice_limits.h>
DlgEditAvatar::DlgEditAvatar(QWidget *parent) : QDialog(parent), image()
{
imageLabel = new QLabel(tr("No image chosen."));
imageLabel->setFixedSize(400, 200);
imageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
imageLabel->setStyleSheet("border: 1px solid #000");
textLabel = new QLabel(tr("To change your avatar, choose a new image.\nTo remove your current avatar, confirm "
"without choosing a new image."));
browseButton = new QPushButton(tr("Browse..."));
connect(browseButton, &QPushButton::clicked, this, &DlgEditAvatar::actBrowse);
QGridLayout *grid = new QGridLayout;
grid->addWidget(imageLabel, 0, 0, 1, 2);
grid->addWidget(textLabel, 1, 0);
grid->addWidget(browseButton, 1, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgEditAvatar::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditAvatar::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Change avatar"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgEditAvatar::actOk()
{
accept();
}
void DlgEditAvatar::actBrowse()
{
QString fileName =
QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::homePath(), tr("Image Files (*.png *.jpg *.bmp)"));
if (fileName.isEmpty()) {
imageLabel->setText(tr("No image chosen."));
return;
}
QImageReader imgReader;
imgReader.setDecideFormatFromContent(true);
imgReader.setFileName(fileName);
if (!imgReader.read(&image)) {
qCWarning(DlgEditAvatarLog) << "Avatar image loading failed for file:" << fileName;
imageLabel->setText(tr("Invalid image chosen."));
return;
}
imageLabel->setPixmap(QPixmap::fromImage(image).scaled(400, 200, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
QByteArray DlgEditAvatar::getImage()
{
if (image.isNull()) {
return QByteArray();
}
for (;;) {
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");
if (ba.length() > MAX_FILE_LENGTH) {
image = image.scaledToWidth(image.width() / 2); // divide the amount of pixels in four to get the size down
} else {
return ba;
}
}
}

View file

@ -0,0 +1,37 @@
/**
* @file dlg_edit_avatar.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_EDITAVATAR_H
#define DLG_EDITAVATAR_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
#include <QLoggingCategory>
inline Q_LOGGING_CATEGORY(DlgEditAvatarLog, "dlg_edit_avatar");
class QLabel;
class QPushButton;
class QCheckBox;
class DlgEditAvatar : public QDialog
{
Q_OBJECT
public:
explicit DlgEditAvatar(QWidget *parent = nullptr);
QByteArray getImage();
private slots:
void actOk();
void actBrowse();
private:
QImage image;
QLabel *textLabel, *imageLabel;
QPushButton *browseButton;
};
#endif

View file

@ -0,0 +1,71 @@
#include "dlg_edit_password.h"
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
{
oldPasswordLabel = new QLabel(tr("Old password:"));
oldPasswordEdit = new QLineEdit();
oldPasswordEdit->setMaxLength(MAX_NAME_LENGTH);
auto &servers = SettingsCache::instance().servers();
if (servers.getSavePassword()) {
oldPasswordEdit->setText(servers.getPassword());
}
oldPasswordLabel->setBuddy(oldPasswordEdit);
oldPasswordEdit->setEchoMode(QLineEdit::Password);
newPasswordLabel = new QLabel(tr("New password:"));
newPasswordEdit = new QLineEdit();
newPasswordEdit->setMaxLength(MAX_NAME_LENGTH);
newPasswordLabel->setBuddy(newPasswordLabel);
newPasswordEdit->setEchoMode(QLineEdit::Password);
newPasswordLabel2 = new QLabel(tr("Confirm new password:"));
newPasswordEdit2 = new QLineEdit();
newPasswordEdit2->setMaxLength(MAX_NAME_LENGTH);
newPasswordLabel2->setBuddy(newPasswordLabel2);
newPasswordEdit2->setEchoMode(QLineEdit::Password);
QGridLayout *grid = new QGridLayout;
grid->addWidget(oldPasswordLabel, 0, 0);
grid->addWidget(oldPasswordEdit, 0, 1);
grid->addWidget(newPasswordLabel, 1, 0);
grid->addWidget(newPasswordEdit, 1, 1);
grid->addWidget(newPasswordLabel2, 2, 0);
grid->addWidget(newPasswordEdit2, 2, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgEditPassword::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditPassword::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Change password"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgEditPassword::actOk()
{
// TODO this stuff should be using qvalidators
if (newPasswordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
return;
} else if (newPasswordEdit->text() != newPasswordEdit2->text()) {
QMessageBox::warning(this, tr("Error"), tr("The new passwords don't match."));
return;
}
accept();
}

View file

@ -0,0 +1,39 @@
/**
* @file dlg_edit_password.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_EDITPASSWORD_H
#define DLG_EDITPASSWORD_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgEditPassword : public QDialog
{
Q_OBJECT
public:
explicit DlgEditPassword(QWidget *parent = nullptr);
QString getOldPassword() const
{
return oldPasswordEdit->text();
}
QString getNewPassword() const
{
return newPasswordEdit->text();
}
private slots:
void actOk();
private:
QLabel *oldPasswordLabel, *newPasswordLabel, *newPasswordLabel2;
QLineEdit *oldPasswordEdit, *newPasswordEdit, *newPasswordEdit2;
};
#endif

View file

@ -0,0 +1,200 @@
#include "dlg_edit_tokens.h"
#include "../interface/widgets/utility/get_text_with_max.h"
#include "../main.h"
#include <QAction>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QToolBar>
#include <QTreeView>
#include <QVBoxLayout>
#include <libcockatrice/card/card_database/card_database.h>
#include <libcockatrice/card/card_database/card_database_manager.h>
#include <libcockatrice/card/card_database/model/card_database_model.h>
#include <libcockatrice/card/card_database/model/token/token_edit_model.h>
#include <libcockatrice/utility/trice_limits.h>
DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nullptr)
{
nameLabel = new QLabel(tr("&Name:"));
nameEdit = new QLineEdit;
nameEdit->setMaxLength(MAX_NAME_LENGTH);
nameEdit->setEnabled(false);
nameLabel->setBuddy(nameEdit);
colorLabel = new QLabel(tr("C&olor:"));
colorEdit = new QComboBox;
colorEdit->addItem(tr("white"), QChar('w'));
colorEdit->addItem(tr("blue"), QChar('u'));
colorEdit->addItem(tr("black"), QChar('b'));
colorEdit->addItem(tr("red"), QChar('r'));
colorEdit->addItem(tr("green"), QChar('g'));
colorEdit->addItem(tr("multicolor"), QChar('m'));
colorEdit->addItem(tr("colorless"), QChar());
colorLabel->setBuddy(colorEdit);
connect(colorEdit, qOverload<int>(&QComboBox::currentIndexChanged), this, &DlgEditTokens::colorChanged);
ptLabel = new QLabel(tr("&P/T:"));
ptEdit = new QLineEdit;
ptEdit->setMaxLength(MAX_NAME_LENGTH);
ptLabel->setBuddy(ptEdit);
connect(ptEdit, &QLineEdit::textChanged, this, &DlgEditTokens::ptChanged);
annotationLabel = new QLabel(tr("&Annotation:"));
annotationEdit = new QLineEdit;
annotationEdit->setMaxLength(MAX_NAME_LENGTH);
annotationLabel->setBuddy(annotationEdit);
connect(annotationEdit, &QLineEdit::textChanged, this, &DlgEditTokens::annotationChanged);
auto *grid = new QGridLayout;
grid->addWidget(nameLabel, 0, 0);
grid->addWidget(nameEdit, 0, 1);
grid->addWidget(colorLabel, 1, 0);
grid->addWidget(colorEdit, 1, 1);
grid->addWidget(ptLabel, 2, 0);
grid->addWidget(ptEdit, 2, 1);
grid->addWidget(annotationLabel, 3, 0);
grid->addWidget(annotationEdit, 3, 1);
QGroupBox *tokenDataGroupBox = new QGroupBox(tr("Token data"));
tokenDataGroupBox->setLayout(grid);
databaseModel = new CardDatabaseModel(CardDatabaseManager::getInstance(), false, this);
databaseModel->setObjectName("databaseModel");
cardDatabaseDisplayModel = new TokenEditModel(this);
cardDatabaseDisplayModel->setSourceModel(databaseModel);
cardDatabaseDisplayModel->setIsToken(CardDatabaseDisplayModel::ShowTrue);
chooseTokenView = new QTreeView;
chooseTokenView->setModel(cardDatabaseDisplayModel);
chooseTokenView->setUniformRowHeights(true);
chooseTokenView->setRootIsDecorated(false);
chooseTokenView->setAlternatingRowColors(true);
chooseTokenView->setSortingEnabled(true);
chooseTokenView->sortByColumn(0, Qt::AscendingOrder);
chooseTokenView->resizeColumnToContents(0);
chooseTokenView->header()->setStretchLastSection(false);
chooseTokenView->header()->hideSection(1);
chooseTokenView->header()->hideSection(2);
chooseTokenView->header()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
chooseTokenView->header()->setSectionResizeMode(4, QHeaderView::ResizeToContents);
connect(chooseTokenView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&DlgEditTokens::tokenSelectionChanged);
QAction *aAddToken = new QAction(tr("Add token"), this);
aAddToken->setIcon(QPixmap("theme:icons/increment"));
connect(aAddToken, &QAction::triggered, this, &DlgEditTokens::actAddToken);
QAction *aRemoveToken = new QAction(tr("Remove token"), this);
aRemoveToken->setIcon(QPixmap("theme:icons/decrement"));
connect(aRemoveToken, &QAction::triggered, this, &DlgEditTokens::actRemoveToken);
auto *databaseToolBar = new QToolBar;
databaseToolBar->addAction(aAddToken);
databaseToolBar->addAction(aRemoveToken);
auto *leftVBox = new QVBoxLayout;
leftVBox->addWidget(chooseTokenView);
leftVBox->addWidget(databaseToolBar);
auto *hbox = new QHBoxLayout;
hbox->addLayout(leftVBox);
hbox->addWidget(tokenDataGroupBox);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgEditTokens::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditTokens::reject);
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(hbox);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Edit custom tokens"));
}
void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QModelIndex & /* previous */)
{
const QModelIndex realIndex = cardDatabaseDisplayModel->mapToSource(current);
if (current.row() >= 0) {
currentCard = databaseModel->getCard(realIndex.row());
} else {
currentCard.clear();
}
if (currentCard) {
nameEdit->setText(currentCard->getName());
const QChar cardColor = currentCard->getColorChar();
colorEdit->setCurrentIndex(colorEdit->findData(cardColor, Qt::UserRole, Qt::MatchFixedString));
ptEdit->setText(currentCard->getPowTough());
annotationEdit->setText(currentCard->getText());
} else {
nameEdit->setText("");
colorEdit->setCurrentIndex(colorEdit->findData(QChar(), Qt::UserRole, Qt::MatchFixedString));
ptEdit->setText("");
annotationEdit->setText("");
}
}
void DlgEditTokens::actAddToken()
{
QString name;
for (;;) {
name = getTextWithMax(this, tr("Add token"), tr("Please enter the name of the token:"));
if (name.isEmpty())
return;
if (databaseModel->getDatabase()->query()->getCardInfo(name)) {
QMessageBox::critical(this, tr("Error"),
tr("The chosen name conflicts with an existing card or token.\nMake sure to enable "
"the 'Token' set in the \"Manage sets\" dialog to display them correctly."));
} else {
break;
}
}
QString setName = CardSet::TOKENS_SETNAME;
SetToPrintingsMap sets;
sets[setName].append(PrintingInfo(databaseModel->getDatabase()->getSet(setName)));
CardInfoPtr card = CardInfo::newInstance(name, "", true, QVariantHash(), QList<CardRelation *>(),
QList<CardRelation *>(), sets, false, false, -1, false);
card->setCardType("Token");
databaseModel->getDatabase()->addCard(card);
}
void DlgEditTokens::actRemoveToken()
{
if (currentCard) {
CardInfoPtr cardToRemove = currentCard; // the currentCard property gets modified during db->removeCard()
currentCard.clear();
databaseModel->getDatabase()->removeCard(cardToRemove);
}
}
void DlgEditTokens::colorChanged(int colorIndex)
{
if (currentCard)
currentCard->setColors(QString(colorEdit->itemData(colorIndex).toChar()));
}
void DlgEditTokens::ptChanged(const QString &_pt)
{
if (currentCard)
currentCard->setPowTough(_pt);
}
void DlgEditTokens::annotationChanged(const QString &_annotation)
{
if (currentCard)
currentCard->setText(_annotation);
}

View file

@ -0,0 +1,47 @@
/**
* @file dlg_edit_tokens.h
* @ingroup GameDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_EDIT_TOKENS_H
#define DLG_EDIT_TOKENS_H
#include <QDialog>
#include <libcockatrice/card/card_info.h>
class QModelIndex;
class CardDatabaseModel;
class TokenEditModel;
class QLabel;
class QComboBox;
class QLineEdit;
class QTreeView;
class DlgEditTokens : public QDialog
{
Q_OBJECT
private slots:
void tokenSelectionChanged(const QModelIndex &current, const QModelIndex &previous);
void colorChanged(int _colorIndex);
void ptChanged(const QString &_pt);
void annotationChanged(const QString &_annotation);
void actAddToken();
void actRemoveToken();
private:
CardInfoPtr currentCard;
CardDatabaseModel *databaseModel;
TokenEditModel *cardDatabaseDisplayModel;
QStringList predefinedTokens;
QLabel *nameLabel, *colorLabel, *ptLabel, *annotationLabel;
QComboBox *colorEdit;
QLineEdit *nameEdit, *ptEdit, *annotationEdit;
QTreeView *chooseTokenView;
public:
explicit DlgEditTokens(QWidget *parent = nullptr);
};
#endif

View file

@ -0,0 +1,66 @@
#include "dlg_edit_user.h"
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgEditUser::DlgEditUser(QWidget *parent, QString email, QString country, QString realName) : QDialog(parent)
{
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailEdit);
emailEdit->setText(email);
countryLabel = new QLabel(tr("Country:"));
countryEdit = new QComboBox();
countryLabel->setBuddy(countryEdit);
countryEdit->insertItem(0, tr("Undefined"));
countryEdit->setCurrentIndex(0);
QStringList countries = SettingsCache::instance().getCountries();
int i = 1;
for (const QString &c : countries) {
countryEdit->addItem(QPixmap("theme:countries/" + c.toLower()), c);
if (c == country)
countryEdit->setCurrentIndex(i);
++i;
}
realnameLabel = new QLabel(tr("Real name:"));
realnameEdit = new QLineEdit();
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
realnameLabel->setBuddy(realnameEdit);
realnameEdit->setText(realName);
QGridLayout *grid = new QGridLayout;
grid->addWidget(emailLabel, 0, 0);
grid->addWidget(emailEdit, 0, 1);
grid->addWidget(countryLabel, 2, 0);
grid->addWidget(countryEdit, 2, 1);
grid->addWidget(realnameLabel, 3, 0);
grid->addWidget(realnameEdit, 3, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgEditUser::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgEditUser::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Edit user profile"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgEditUser::actOk()
{
accept();
}

View file

@ -0,0 +1,47 @@
/**
* @file dlg_edit user.h
* @ingroup NetworkDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_EDITUSER_H
#define DLG_EDITUSER_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgEditUser : public QDialog
{
Q_OBJECT
public:
explicit DlgEditUser(QWidget *parent = nullptr,
QString email = QString(),
QString country = QString(),
QString realName = QString());
QString getEmail() const
{
return emailEdit->text();
}
QString getCountry() const
{
return countryEdit->currentIndex() == 0 ? "" : countryEdit->currentText();
}
QString getRealName() const
{
return realnameEdit->text();
}
private slots:
void actOk();
private:
QLabel *emailLabel, *countryLabel, *realnameLabel;
QLineEdit *emailEdit, *realnameEdit;
QComboBox *countryEdit;
};
#endif

View file

@ -0,0 +1,289 @@
#include "dlg_filter_games.h"
#include <QCheckBox>
#include <QComboBox>
#include <QCryptographicHash>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
const GamesProxyModel *_gamesProxyModel,
QWidget *parent)
: QDialog(parent), allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel),
gameAgeMap({{QTime(), tr("no limit")},
{QTime(0, 5), tr("5 minutes")},
{QTime(0, 10), tr("10 minutes")},
{QTime(0, 30), tr("30 minutes")},
{QTime(1, 0), tr("1 hour")},
{QTime(2, 0), tr("2 hours")}})
{
hideBuddiesOnlyGames = new QCheckBox(tr("Hide 'buddies only' games"));
hideBuddiesOnlyGames->setChecked(gamesProxyModel->getHideBuddiesOnlyGames());
hideFullGames = new QCheckBox(tr("Hide full games"));
hideFullGames->setChecked(gamesProxyModel->getHideFullGames());
hideGamesThatStarted = new QCheckBox(tr("Hide games that have started"));
hideGamesThatStarted->setChecked(gamesProxyModel->getHideGamesThatStarted());
hidePasswordProtectedGames = new QCheckBox(tr("Hide password protected games"));
hidePasswordProtectedGames->setChecked(gamesProxyModel->getHidePasswordProtectedGames());
hideIgnoredUserGames = new QCheckBox(tr("Hide 'ignored user' games"));
hideIgnoredUserGames->setChecked(gamesProxyModel->getHideIgnoredUserGames());
hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddy"));
hideNotBuddyCreatedGames->setChecked(gamesProxyModel->getHideNotBuddyCreatedGames());
hideOpenDecklistGames = new QCheckBox(tr("Hide games with forced open decklists"));
hideOpenDecklistGames->setChecked(gamesProxyModel->getHideOpenDecklistGames());
maxGameAgeComboBox = new QComboBox();
maxGameAgeComboBox->setEditable(false);
maxGameAgeComboBox->addItems(gameAgeMap.values());
QTime gameAge = gamesProxyModel->getMaxGameAge();
maxGameAgeComboBox->setCurrentIndex(gameAgeMap.keys().indexOf(gameAge)); // index is -1 if unknown
auto *maxGameAgeLabel = new QLabel(tr("&Newer than:"));
maxGameAgeLabel->setBuddy(maxGameAgeComboBox);
gameNameFilterEdit = new QLineEdit;
gameNameFilterEdit->setText(gamesProxyModel->getGameNameFilter());
auto *gameNameFilterLabel = new QLabel(tr("Game &description:"));
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
creatorNameFilterEdit = new QLineEdit;
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilter());
auto *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
auto *generalGrid = new QGridLayout;
generalGrid->addWidget(gameNameFilterLabel, 0, 0);
generalGrid->addWidget(gameNameFilterEdit, 0, 1);
generalGrid->addWidget(creatorNameFilterLabel, 1, 0);
generalGrid->addWidget(creatorNameFilterEdit, 1, 1);
generalGrid->addWidget(maxGameAgeLabel, 2, 0);
generalGrid->addWidget(maxGameAgeComboBox, 2, 1);
generalGroupBox = new QGroupBox(tr("General"));
generalGroupBox->setLayout(generalGrid);
auto *gameTypeFilterLayout = new QVBoxLayout;
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
while (gameTypesIterator.hasNext()) {
gameTypesIterator.next();
auto *temp = new QCheckBox(gameTypesIterator.value());
temp->setChecked(gamesProxyModel->getGameTypeFilter().contains(gameTypesIterator.key()));
gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp);
gameTypeFilterLayout->addWidget(temp);
}
QGroupBox *gameTypeFilterGroupBox;
if (!allGameTypes.isEmpty()) {
gameTypeFilterGroupBox = new QGroupBox(tr("&Game types"));
gameTypeFilterGroupBox->setLayout(gameTypeFilterLayout);
} else
gameTypeFilterGroupBox = nullptr;
auto *maxPlayersFilterMinLabel = new QLabel(tr("at &least:"));
maxPlayersFilterMinSpinBox = new QSpinBox;
maxPlayersFilterMinSpinBox->setMinimum(0);
maxPlayersFilterMinSpinBox->setMaximum(99);
maxPlayersFilterMinSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMin());
maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox);
auto *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
maxPlayersFilterMaxSpinBox = new QSpinBox;
maxPlayersFilterMaxSpinBox->setMinimum(0);
maxPlayersFilterMaxSpinBox->setMaximum(99);
maxPlayersFilterMaxSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMax());
maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox);
auto *maxPlayersFilterLayout = new QGridLayout;
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinLabel, 0, 0);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinSpinBox, 0, 1);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxLabel, 1, 0);
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxSpinBox, 1, 1);
auto *maxPlayersGroupBox = new QGroupBox(tr("Maximum player count"));
maxPlayersGroupBox->setLayout(maxPlayersFilterLayout);
auto *restrictionsLayout = new QGridLayout;
restrictionsLayout->addWidget(hideFullGames, 0, 0);
restrictionsLayout->addWidget(hideGamesThatStarted, 1, 0);
restrictionsLayout->addWidget(hidePasswordProtectedGames, 2, 0);
restrictionsLayout->addWidget(hideBuddiesOnlyGames, 3, 0);
restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0);
restrictionsLayout->addWidget(hideNotBuddyCreatedGames, 5, 0);
restrictionsLayout->addWidget(hideOpenDecklistGames, 6, 0);
auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
restrictionsGroupBox->setLayout(restrictionsLayout);
showOnlyIfSpectatorsCanWatch = new QCheckBox(tr("Show games only if &spectators can watch"));
showOnlyIfSpectatorsCanWatch->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanWatch());
connect(showOnlyIfSpectatorsCanWatch, &QCheckBox::toggled, this,
&DlgFilterGames::toggleSpectatorCheckboxEnabledness);
showSpectatorPasswordProtected = new QCheckBox(tr("Show spectator password p&rotected games"));
showSpectatorPasswordProtected->setChecked(gamesProxyModel->getShowSpectatorPasswordProtected());
showOnlyIfSpectatorsCanChat = new QCheckBox(tr("Show only if spectators can ch&at"));
showOnlyIfSpectatorsCanChat->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanChat());
showOnlyIfSpectatorsCanSeeHands = new QCheckBox(tr("Show only if spectators can see &hands"));
showOnlyIfSpectatorsCanSeeHands->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanSeeHands());
toggleSpectatorCheckboxEnabledness(getShowOnlyIfSpectatorsCanWatch());
auto *spectatorsLayout = new QGridLayout;
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanWatch, 0, 0);
spectatorsLayout->addWidget(showSpectatorPasswordProtected, 1, 0);
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanChat, 2, 0);
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanSeeHands, 3, 0);
auto *spectatorsGroupBox = new QGroupBox(tr("Spectators"));
spectatorsGroupBox->setLayout(spectatorsLayout);
auto *leftGrid = new QGridLayout;
leftGrid->addWidget(generalGroupBox, 0, 0, 1, 2);
leftGrid->addWidget(maxPlayersGroupBox, 2, 0, 1, 2);
leftGrid->addWidget(restrictionsGroupBox, 3, 0, 1, 2);
auto *leftColumn = new QVBoxLayout;
leftColumn->addLayout(leftGrid);
leftColumn->addStretch();
auto *rightGrid = new QGridLayout;
rightGrid->addWidget(gameTypeFilterGroupBox, 0, 0, 1, 1);
rightGrid->addWidget(spectatorsGroupBox, 1, 0, 1, 1);
auto *rightColumn = new QVBoxLayout;
rightColumn->addLayout(rightGrid);
rightColumn->addStretch();
auto *hbox = new QHBoxLayout;
hbox->addLayout(leftColumn);
hbox->addLayout(rightColumn);
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgFilterGames::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgFilterGames::reject);
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(hbox);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Filter games"));
setFixedHeight(sizeHint().height());
}
void DlgFilterGames::actOk()
{
accept();
}
void DlgFilterGames::toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled)
{
showSpectatorPasswordProtected->setDisabled(!spectatorsEnabled);
showOnlyIfSpectatorsCanChat->setDisabled(!spectatorsEnabled);
showOnlyIfSpectatorsCanSeeHands->setDisabled(!spectatorsEnabled);
}
bool DlgFilterGames::getHideFullGames() const
{
return hideFullGames->isChecked();
}
bool DlgFilterGames::getHideGamesThatStarted() const
{
return hideGamesThatStarted->isChecked();
}
bool DlgFilterGames::getHideBuddiesOnlyGames() const
{
return hideBuddiesOnlyGames->isChecked();
}
bool DlgFilterGames::getHidePasswordProtectedGames() const
{
return hidePasswordProtectedGames->isChecked();
}
bool DlgFilterGames::getHideIgnoredUserGames() const
{
return hideIgnoredUserGames->isChecked();
}
bool DlgFilterGames::getHideNotBuddyCreatedGames() const
{
return hideNotBuddyCreatedGames->isChecked();
}
bool DlgFilterGames::getHideOpenDecklistGames() const
{
return hideOpenDecklistGames->isChecked();
}
QString DlgFilterGames::getGameNameFilter() const
{
return gameNameFilterEdit->text();
}
QString DlgFilterGames::getCreatorNameFilter() const
{
return creatorNameFilterEdit->text();
}
QSet<int> DlgFilterGames::getGameTypeFilter() const
{
QSet<int> result;
QMapIterator<int, QCheckBox *> i(gameTypeFilterCheckBoxes);
while (i.hasNext()) {
i.next();
if (i.value()->isChecked())
result.insert(i.key());
}
return result;
}
int DlgFilterGames::getMaxPlayersFilterMin() const
{
return maxPlayersFilterMinSpinBox->value();
}
int DlgFilterGames::getMaxPlayersFilterMax() const
{
return maxPlayersFilterMaxSpinBox->value();
}
QTime DlgFilterGames::getMaxGameAge() const
{
int index = maxGameAgeComboBox->currentIndex();
if (index < 0 || index >= gameAgeMap.size()) { // index is out of bounds
return gamesProxyModel->getMaxGameAge(); // leave the setting unchanged
}
return gameAgeMap.keys().at(index);
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanWatch() const
{
return showOnlyIfSpectatorsCanWatch->isChecked();
}
bool DlgFilterGames::getShowSpectatorPasswordProtected() const
{
return showSpectatorPasswordProtected->isEnabled() && showSpectatorPasswordProtected->isChecked();
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanChat() const
{
return showOnlyIfSpectatorsCanChat->isEnabled() && showOnlyIfSpectatorsCanChat->isChecked();
}
bool DlgFilterGames::getShowOnlyIfSpectatorsCanSeeHands() const
{
return showOnlyIfSpectatorsCanSeeHands->isEnabled() && showOnlyIfSpectatorsCanSeeHands->isChecked();
}

View file

@ -0,0 +1,89 @@
/**
* @file dlg_filter_games.h
* @ingroup RoomDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_FILTER_GAMES_H
#define DLG_FILTER_GAMES_H
#include "../interface/widgets/server/games_model.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QMap>
#include <QSet>
#include <QTime>
class QCheckBox;
class QComboBox;
class QGroupBox;
class QLineEdit;
class QSpinBox;
class DlgFilterGames : public QDialog
{
Q_OBJECT
private:
QGroupBox *generalGroupBox;
QCheckBox *hideBuddiesOnlyGames;
QCheckBox *hideFullGames;
QCheckBox *hideGamesThatStarted;
QCheckBox *hidePasswordProtectedGames;
QCheckBox *hideIgnoredUserGames;
QCheckBox *hideNotBuddyCreatedGames;
QCheckBox *hideOpenDecklistGames;
QLineEdit *gameNameFilterEdit;
QLineEdit *creatorNameFilterEdit;
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
QSpinBox *maxPlayersFilterMinSpinBox;
QSpinBox *maxPlayersFilterMaxSpinBox;
QComboBox *maxGameAgeComboBox;
QCheckBox *showOnlyIfSpectatorsCanWatch;
QCheckBox *showSpectatorPasswordProtected;
QCheckBox *showOnlyIfSpectatorsCanChat;
QCheckBox *showOnlyIfSpectatorsCanSeeHands;
const QMap<int, QString> &allGameTypes;
const GamesProxyModel *gamesProxyModel;
private slots:
void actOk();
void toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled);
public:
DlgFilterGames(const QMap<int, QString> &_allGameTypes,
const GamesProxyModel *_gamesProxyModel,
QWidget *parent = nullptr);
bool getHideFullGames() const;
bool getHideGamesThatStarted() const;
bool getHidePasswordProtectedGames() const;
void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden);
bool getHideBuddiesOnlyGames() const;
void setHideBuddiesOnlyGames(bool _hideBuddiesOnlyGames);
bool getHideOpenDecklistGames() const;
void setHideOpenDecklistGames(bool _hideOpenDecklistGames);
bool getHideIgnoredUserGames() const;
void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
bool getHideNotBuddyCreatedGames() const;
QString getGameNameFilter() const;
void setGameNameFilter(const QString &_gameNameFilter);
QString getCreatorNameFilter() const;
void setCreatorNameFilter(const QString &_creatorNameFilter);
QSet<int> getGameTypeFilter() const;
void setGameTypeFilter(const QSet<int> &_gameTypeFilter);
int getMaxPlayersFilterMin() const;
int getMaxPlayersFilterMax() const;
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
QTime getMaxGameAge() const;
const QMap<QTime, QString> gameAgeMap;
bool getShowOnlyIfSpectatorsCanWatch() const;
bool getShowSpectatorPasswordProtected() const;
bool getShowOnlyIfSpectatorsCanChat() const;
bool getShowOnlyIfSpectatorsCanSeeHands() const;
};
#endif

View file

@ -0,0 +1,106 @@
#include "dlg_forgot_password_challenge.h"
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialog(parent)
{
QString lastfphost;
QString lastfpport;
QString lastfpplayername;
ServersSettings &servers = SettingsCache::instance().servers();
lastfphost = servers.getHostname();
lastfpport = servers.getPort();
lastfpplayername = servers.getPlayerName();
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
lastfphost = servers.getFPHostname();
lastfpport = servers.getFPPort();
lastfpplayername = servers.getFPPlayerName();
}
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
QMessageBox::warning(this, tr("Reset Password Challenge Warning"),
tr("A problem has occurred. Please try to request a new password again."));
reject();
}
infoLabel =
new QLabel(tr("Enter the information of the server and the account you'd like to request a new password for."));
infoLabel->setWordWrap(true);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailLabel);
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
hostLabel->hide();
hostEdit->hide();
portLabel->hide();
portEdit->hide();
playernameLabel->hide();
playernameEdit->hide();
}
QGridLayout *grid = new QGridLayout;
grid->addWidget(infoLabel, 0, 0, 1, 2);
grid->addWidget(hostLabel, 1, 0);
grid->addWidget(hostEdit, 1, 1);
grid->addWidget(portLabel, 2, 0);
grid->addWidget(portEdit, 2, 1);
grid->addWidget(playernameLabel, 3, 0);
grid->addWidget(playernameEdit, 3, 1);
grid->addWidget(emailLabel, 4, 0);
grid->addWidget(emailEdit, 4, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgForgotPasswordChallenge::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordChallenge::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Reset Password Challenge"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgForgotPasswordChallenge::actOk()
{
if (emailEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Reset Password Challenge Error"), tr("The email address can't be empty."));
return;
}
ServersSettings &servers = SettingsCache::instance().servers();
servers.setFPHostName(hostEdit->text());
servers.setFPPort(portEdit->text());
servers.setFPPlayerName(playernameEdit->text());
accept();
}

View file

@ -0,0 +1,47 @@
/**
* @file dlg_forgot_password_challenge.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_FORGOTPASSWORDCHALLENGE_H
#define DLG_FORGOTPASSWORDCHALLENGE_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgForgotPasswordChallenge : public QDialog
{
Q_OBJECT
public:
explicit DlgForgotPasswordChallenge(QWidget *parent = nullptr);
QString getHost() const
{
return hostEdit->text();
}
int getPort() const
{
return portEdit->text().toInt();
}
QString getPlayerName() const
{
return playernameEdit->text();
}
QString getEmail() const
{
return emailEdit->text();
}
private slots:
void actOk();
private:
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *emailLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit, *emailEdit;
};
#endif

View file

@ -0,0 +1,83 @@
#include "dlg_forgot_password_request.h"
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(parent)
{
QString lastfphost;
QString lastfpport;
QString lastfpplayername;
ServersSettings &servers = SettingsCache::instance().servers();
lastfphost = servers.getHostname();
lastfpport = servers.getPort();
lastfpplayername = servers.getPlayerName();
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
lastfphost = servers.getFPHostname();
lastfpport = servers.getFPPort();
lastfpplayername = servers.getFPPlayerName();
}
infoLabel = new QLabel(tr("Enter the information of the server you'd like to request a new password for."));
infoLabel->setWordWrap(true);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
QGridLayout *grid = new QGridLayout;
grid->addWidget(infoLabel, 0, 0, 1, 2);
grid->addWidget(hostLabel, 1, 0);
grid->addWidget(hostEdit, 1, 1);
grid->addWidget(portLabel, 2, 0);
grid->addWidget(portEdit, 2, 1);
grid->addWidget(playernameLabel, 3, 0);
grid->addWidget(playernameEdit, 3, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgForgotPasswordRequest::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordRequest::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Reset Password Request"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgForgotPasswordRequest::actOk()
{
if (playernameEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The player name can't be empty."));
return;
}
ServersSettings &servers = SettingsCache::instance().servers();
servers.setFPHostName(hostEdit->text());
servers.setFPPort(portEdit->text());
servers.setFPPlayerName(playernameEdit->text());
accept();
}

View file

@ -0,0 +1,43 @@
/**
* @file dlg_forgot_password_request.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_FORGOTPASSWORDREQUEST_H
#define DLG_FORGOTPASSWORDREQUEST_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgForgotPasswordRequest : public QDialog
{
Q_OBJECT
public:
explicit DlgForgotPasswordRequest(QWidget *parent = nullptr);
QString getHost() const
{
return hostEdit->text();
}
int getPort() const
{
return portEdit->text().toInt();
}
QString getPlayerName() const
{
return playernameEdit->text();
}
private slots:
void actOk();
private:
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit;
};
#endif

View file

@ -0,0 +1,140 @@
#include "dlg_forgot_password_reset.h"
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent)
{
QString lastfphost;
QString lastfpport;
QString lastfpplayername;
ServersSettings &servers = SettingsCache::instance().servers();
lastfphost = servers.getHostname();
lastfpport = servers.getPort();
lastfpplayername = servers.getPlayerName();
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
lastfphost = servers.getFPHostname();
lastfpport = servers.getFPPort();
lastfpplayername = servers.getFPPlayerName();
}
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
QMessageBox::warning(this, tr("Reset Password Warning"),
tr("A problem has occurred. Please try to request a new password again."));
reject();
}
infoLabel = new QLabel(tr("Enter the received token and the new password in order to set your new password."));
infoLabel->setWordWrap(true);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
tokenLabel = new QLabel(tr("Token:"));
tokenEdit = new QLineEdit();
tokenEdit->setMaxLength(MAX_NAME_LENGTH);
tokenLabel->setBuddy(tokenLabel);
newpasswordLabel = new QLabel(tr("New Password:"));
newpasswordEdit = new QLineEdit();
newpasswordEdit->setMaxLength(MAX_NAME_LENGTH);
newpasswordLabel->setBuddy(newpasswordEdit);
newpasswordEdit->setEchoMode(QLineEdit::Password);
newpasswordverifyLabel = new QLabel(tr("New Password:"));
newpasswordverifyEdit = new QLineEdit();
newpasswordverifyEdit->setMaxLength(MAX_NAME_LENGTH);
newpasswordverifyLabel->setBuddy(newpasswordEdit);
newpasswordverifyEdit->setEchoMode(QLineEdit::Password);
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
hostLabel->hide();
hostEdit->hide();
portLabel->hide();
portEdit->hide();
playernameLabel->hide();
playernameEdit->hide();
}
QGridLayout *grid = new QGridLayout;
grid->addWidget(infoLabel, 0, 0, 1, 2);
grid->addWidget(hostLabel, 1, 0);
grid->addWidget(hostEdit, 1, 1);
grid->addWidget(portLabel, 2, 0);
grid->addWidget(portEdit, 2, 1);
grid->addWidget(playernameLabel, 3, 0);
grid->addWidget(playernameEdit, 3, 1);
grid->addWidget(tokenLabel, 4, 0);
grid->addWidget(tokenEdit, 4, 1);
grid->addWidget(newpasswordLabel, 5, 0);
grid->addWidget(newpasswordEdit, 5, 1);
grid->addWidget(newpasswordverifyLabel, 6, 0);
grid->addWidget(newpasswordverifyEdit, 6, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgForgotPasswordReset::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgForgotPasswordReset::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Reset Password"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgForgotPasswordReset::actOk()
{
if (playernameEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The player name can't be empty."));
return;
}
if (tokenEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The token can't be empty."));
return;
}
if (newpasswordEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The new password can't be empty."));
return;
}
// TODO this stuff should be using qvalidators
if (newpasswordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
return;
} else if (newpasswordEdit->text() != newpasswordverifyEdit->text()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The passwords do not match."));
return;
}
ServersSettings &servers = SettingsCache::instance().servers();
servers.setFPHostName(hostEdit->text());
servers.setFPPort(portEdit->text());
servers.setFPPlayerName(playernameEdit->text());
accept();
}

View file

@ -0,0 +1,52 @@
/**
* @file dlg_forgot_password_reset.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_FORGOTPASSWORDRESET_H
#define DLG_FORGOTPASSWORDRESET_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgForgotPasswordReset : public QDialog
{
Q_OBJECT
public:
explicit DlgForgotPasswordReset(QWidget *parent = nullptr);
QString getHost() const
{
return hostEdit->text();
}
int getPort() const
{
return portEdit->text().toInt();
}
QString getPlayerName() const
{
return playernameEdit->text();
}
QString getToken() const
{
return tokenEdit->text();
}
QString getPassword() const
{
return newpasswordEdit->text();
}
private slots:
void actOk();
private:
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *tokenLabel, *newpasswordLabel,
*newpasswordverifyLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit, *tokenEdit, *newpasswordEdit, *newpasswordverifyEdit;
};
#endif

View file

@ -0,0 +1,22 @@
#include "dlg_load_deck.h"
#include <libcockatrice/deck_list/deck_loader.h>
#include <libcockatrice/settings/cache_settings.h>
DlgLoadDeck::DlgLoadDeck(QWidget *parent) : QFileDialog(parent, tr("Load Deck"))
{
QString startingDir = SettingsCache::instance().recents().getLatestDeckDirPath();
if (startingDir.isEmpty()) {
startingDir = SettingsCache::instance().getDeckPath();
}
setDirectory(startingDir);
setNameFilters(DeckLoader::FILE_NAME_FILTERS);
connect(this, &DlgLoadDeck::accepted, this, &DlgLoadDeck::actAccepted);
}
void DlgLoadDeck::actAccepted()
{
SettingsCache::instance().recents().setLatestDeckDirPath(directory().absolutePath());
}

View file

@ -0,0 +1,27 @@
/**
* @file dlg_load_deck.h
* @ingroup LocalDeckStorageDialogs
* @ingroup Lobby
* @brief TODO: Document this.
*/
#ifndef DLG_LOAD_DECK_H
#define DLG_LOAD_DECK_H
#include <QFileDialog>
/**
* The file dialog for "Load Deck" operations.
* Handles remembering the most recently used deck loading directory.
*/
class DlgLoadDeck : public QFileDialog
{
Q_OBJECT
void actAccepted();
public:
explicit DlgLoadDeck(QWidget *parent = nullptr);
};
#endif // DLG_LOAD_DECK_H

View file

@ -0,0 +1,178 @@
#include "dlg_load_deck_from_clipboard.h"
#include "dlg_settings.h"
#include <QApplication>
#include <QCheckBox>
#include <QClipboard>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QTextStream>
#include <QVBoxLayout>
#include <libcockatrice/deck_list/deck_loader.h>
#include <libcockatrice/settings/cache_settings.h>
/**
* Creates the main layout and connects the signals that are common to all versions of this window
*/
AbstractDlgDeckTextEdit::AbstractDlgDeckTextEdit(QWidget *parent) : QDialog(parent)
{
contentsEdit = new QPlainTextEdit;
refreshButton = new QPushButton(tr("&Refresh"));
connect(refreshButton, &QPushButton::clicked, this, &AbstractDlgDeckTextEdit::actRefresh);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
connect(buttonBox, &QDialogButtonBox::accepted, this, &AbstractDlgDeckTextEdit::actOK);
connect(buttonBox, &QDialogButtonBox::rejected, this, &AbstractDlgDeckTextEdit::reject);
loadSetNameAndNumberCheckBox = new QCheckBox(tr("Parse Set Name and Number (if available)"));
loadSetNameAndNumberCheckBox->setChecked(true);
auto *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(loadSetNameAndNumberCheckBox);
buttonLayout->addWidget(buttonBox);
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(contentsEdit);
mainLayout->addLayout(buttonLayout);
setLayout(mainLayout);
resize(500, 500);
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
&AbstractDlgDeckTextEdit::refreshShortcuts);
refreshShortcuts();
}
void AbstractDlgDeckTextEdit::refreshShortcuts()
{
refreshButton->setShortcut(
SettingsCache::instance().shortcuts().getSingleShortcut("DlgLoadDeckFromClipboard/refreshButton"));
}
/**
* Replaces the contents of the contentsEdit with the given text.
* @param text The text
*/
void AbstractDlgDeckTextEdit::setText(const QString &text)
{
contentsEdit->setPlainText(text);
}
/**
* Tries to load the current contents of the contentsEdit into the DeckLoader
*
* @param deckLoader The DeckLoader to load the deck into
* @return Whether the loading was successful
*/
bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
{
QString buffer = contentsEdit->toPlainText();
if (buffer.contains("<cockatrice_deck version=\"1\">")) {
return deckLoader->loadFromString_Native(buffer);
}
QTextStream stream(&buffer);
if (deckLoader->loadFromStream_Plain(stream, true)) {
if (loadSetNameAndNumberCheckBox->isChecked()) {
deckLoader->resolveSetNameAndNumberToProviderID();
} else {
deckLoader->clearSetNamesAndNumbers();
}
return true;
}
return false;
}
void AbstractDlgDeckTextEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return && event->modifiers() & Qt::ControlModifier) {
event->accept();
actOK();
return;
}
QDialog::keyPressEvent(event);
}
/**
* Creates the dialog window for the "Load deck from clipboard" action
*
* @param parent The parent widget
*/
DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : AbstractDlgDeckTextEdit(parent), deckList(nullptr)
{
setWindowTitle(tr("Load deck from clipboard"));
DlgLoadDeckFromClipboard::actRefresh();
}
void DlgLoadDeckFromClipboard::actRefresh()
{
setText(QApplication::clipboard()->text());
}
void DlgLoadDeckFromClipboard::actOK()
{
deckList = new DeckLoader;
deckList->setParent(this);
if (loadIntoDeck(deckList)) {
accept();
} else {
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
}
}
/**
* Creates the dialog window for the "Edit deck in clipboard" action
*
* @param deckList The existing deck in the deck editor. Copies the instance
* @param _annotated Whether to add annotations to the text that is loaded from the deck
* @param parent The parent widget
*/
DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent)
: AbstractDlgDeckTextEdit(parent), annotated(_annotated)
{
setWindowTitle(tr("Edit deck in clipboard"));
deckLoader = new DeckLoader(deckList);
deckLoader->setParent(this);
DlgEditDeckInClipboard::actRefresh();
}
/**
* Loads the contents of the DeckList into a String. Always loads it with addSetNameAndNumber=true
* @param deckList The deck to load
* @param addComments Whether to add annotations
* @return A QString
*/
static QString deckListToString(const DeckLoader *deckList, bool addComments)
{
QString buffer;
QTextStream stream(&buffer);
deckList->saveToStream_Plain(stream, addComments);
return buffer;
}
void DlgEditDeckInClipboard::actRefresh()
{
setText(deckListToString(deckLoader, annotated));
}
void DlgEditDeckInClipboard::actOK()
{
if (loadIntoDeck(deckLoader)) {
accept();
} else {
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
}
}

View file

@ -0,0 +1,99 @@
/**
* @file dlg_load_deck_from_clipboard.h
* @ingroup LocalDeckStorageDialogs
* @ingroup Lobby
* @brief TODO: Document this.
*/
#ifndef DLG_LOAD_DECK_FROM_CLIPBOARD_H
#define DLG_LOAD_DECK_FROM_CLIPBOARD_H
#include <QCheckBox>
#include <QDialog>
class DeckLoader;
class QPlainTextEdit;
class QPushButton;
/**
* Base class for dialog windows for actions that involve loading decks from text input.
*/
class AbstractDlgDeckTextEdit : public QDialog
{
Q_OBJECT
private:
QPlainTextEdit *contentsEdit;
QPushButton *refreshButton;
QCheckBox *loadSetNameAndNumberCheckBox;
private slots:
void refreshShortcuts();
public:
explicit AbstractDlgDeckTextEdit(QWidget *parent = nullptr);
/**
* Gets the loaded deck. Only call this method after this dialog window has been successfully exec'd.
*
* The returned DeckLoader is parented to this object; make sure to take ownership of the DeckLoader if you intend
* to use it, since otherwise it will get destroyed once this dlg is destroyed
* @return The DeckLoader
*/
virtual DeckLoader *getDeckList() const = 0;
protected:
void setText(const QString &text);
bool loadIntoDeck(DeckLoader *deckLoader) const;
void keyPressEvent(QKeyEvent *event) override;
protected slots:
virtual void actOK() = 0;
virtual void actRefresh() = 0;
};
/**
* Dialog window for the "Load deck from clipboard" action
*/
class DlgLoadDeckFromClipboard : public AbstractDlgDeckTextEdit
{
Q_OBJECT
protected slots:
void actOK() override;
void actRefresh() override;
private:
DeckLoader *deckList;
public:
explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr);
DeckLoader *getDeckList() const override
{
return deckList;
}
};
/**
* Dialog window for the "Edit deck in clipboard" action
*/
class DlgEditDeckInClipboard : public AbstractDlgDeckTextEdit
{
Q_OBJECT
protected slots:
void actOK() override;
void actRefresh() override;
private:
DeckLoader *deckLoader;
bool annotated;
public:
explicit DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent = nullptr);
DeckLoader *getDeckList() const override
{
return deckLoader;
}
};
#endif

View file

@ -0,0 +1,145 @@
#include "dlg_load_deck_from_website.h"
#include <QApplication>
#include <QClipboard>
#include <QDialogButtonBox>
#include <QEventLoop>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QNetworkReply>
DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent)
{
nam = new QNetworkAccessManager(this);
layout = new QVBoxLayout(this);
setLayout(layout);
instructionLabel = new QLabel(this);
layout->addWidget(instructionLabel);
urlEdit = new QLineEdit(this);
urlEdit->setText(QApplication::clipboard()->text());
layout->addWidget(urlEdit);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
layout->addWidget(buttonBox);
if (testValidUrl()) {
QMetaObject::invokeMethod(this, "accept", Qt::QueuedConnection);
hide();
}
retranslateUi();
}
void DlgLoadDeckFromWebsite::retranslateUi()
{
instructionLabel->setText(tr("Paste a link to a decklist site here to import it.\n(Archidekt, Deckstats, Moxfield, "
"and TappedOut are supported.)"));
}
bool DlgLoadDeckFromWebsite::testValidUrl()
{
ParsedDeckInfo info;
return DeckLinkToApiTransformer::parseDeckUrl(urlEdit->text(), info);
}
void DlgLoadDeckFromWebsite::accept()
{
ParsedDeckInfo info;
if (DeckLinkToApiTransformer::parseDeckUrl(urlEdit->text(), info)) {
qCInfo(DlgLoadDeckFromWebsiteLog) << info.baseUrl << info.deckID << info.fullUrl;
auto jsonParser = createParserForProvider(info.provider);
if (!jsonParser && info.provider != DeckProvider::Deckstats && info.provider != DeckProvider::TappedOut) {
qCWarning(DlgLoadDeckFromWebsiteLog) << "No parser found for provider";
QMessageBox::warning(this, tr("Load Deck from Website"),
tr("No parser available for this deck provider.\n (Archidekt, Deckstats, Moxfield, "
"and TappedOut are supported.)"));
QDialog::reject();
return;
}
QNetworkRequest request(QUrl(info.fullUrl));
QNetworkReply *reply = nam->get(request);
QEventLoop loop;
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
if (reply->error() != QNetworkReply::NoError) {
qCWarning(DlgLoadDeckFromWebsiteLog) << "Network error:" << reply->errorString();
QMessageBox::warning(this, tr("Load Deck from Website"), tr("Network error: %1").arg(reply->errorString()));
reply->deleteLater();
QDialog::reject();
return;
}
QByteArray responseData = reply->readAll();
reply->deleteLater();
// Special handling for Deckstats and TappedOut .txt
if (info.provider == DeckProvider::Deckstats || info.provider == DeckProvider::TappedOut) {
QString deckText = QString::fromUtf8(responseData);
if (deckText.isEmpty()) {
qCWarning(DlgLoadDeckFromWebsiteLog) << "Response is empty";
QMessageBox::warning(this, tr("Load Deck from Website"), tr("Received empty deck data."));
QDialog::reject();
return;
}
// Parse the plain text deck here
DeckLoader *loader = new DeckLoader();
QTextStream stream(&deckText);
loader->loadFromStream_Plain(stream, false);
loader->resolveSetNameAndNumberToProviderID();
deck = loader;
QDialog::accept();
return;
}
// Normal JSON parsing for other providers
QJsonParseError parseError;
QJsonDocument doc = QJsonDocument::fromJson(responseData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qCWarning(DlgLoadDeckFromWebsiteLog) << "JSON parse error:" << parseError.errorString();
QMessageBox::warning(this, tr("Load Deck from Website"),
tr("Failed to parse deck data: %1").arg(parseError.errorString()));
QDialog::reject();
return;
}
deck = jsonParser->parse(doc.object());
QDialog::accept();
} else {
qCInfo(DlgLoadDeckFromWebsiteLog) << "URL not recognized";
QMessageBox::warning(this, tr("Load Deck from Website"),
tr("The provided URL is not recognized as a valid deck URL.\n"
"Valid deck URLs look like this:\n\n"
"https://archidekt.com/decks/9999999\n"
"https://deckstats.net/decks/99999/9999999-your-deck-name/en\n"
"https://moxfield.com/decks/XYZxx-XYZ99Yyy-xyzXzzz\n"
"https://tappedout.net/mtg-decks/your-deck-name/"));
QDialog::reject();
}
}
QSharedPointer<IJsonDeckParser> DlgLoadDeckFromWebsite::createParserForProvider(DeckProvider provider)
{
switch (provider) {
case DeckProvider::Archidekt:
return QSharedPointer<IJsonDeckParser>(new ArchidektJsonParser());
case DeckProvider::Moxfield:
return QSharedPointer<IJsonDeckParser>(new MoxfieldJsonParser());
default:
return QSharedPointer<IJsonDeckParser>(nullptr);
}
}

View file

@ -0,0 +1,47 @@
/**
* @file dlg_load_deck_from_website.h
* @ingroup RemoteDeckStorageDialogs
* @ingroup Lobby
* @brief TODO: Document this.
*/
#ifndef DLG_LOAD_DECK_FROM_WEBSITE_H
#define DLG_LOAD_DECK_FROM_WEBSITE_H
#include "../client/network/parsers/deck_link_to_api_transformer.h"
#include "../client/network/parsers/interface_json_deck_parser.h"
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QNetworkAccessManager>
#include <QVBoxLayout>
inline Q_LOGGING_CATEGORY(DlgLoadDeckFromWebsiteLog, "dlg_load_deck_from_website");
class DlgLoadDeckFromWebsite : public QDialog
{
Q_OBJECT
public:
explicit DlgLoadDeckFromWebsite(QWidget *parent);
void retranslateUi();
bool testValidUrl();
DeckLoader *deck;
DeckLoader *getDeck()
{
return deck;
}
private:
QNetworkAccessManager *nam;
QVBoxLayout *layout;
QLabel *instructionLabel;
QLineEdit *urlEdit;
public slots:
void accept() override;
QSharedPointer<IJsonDeckParser> createParserForProvider(DeckProvider provider);
};
#endif // DLG_LOAD_DECK_FROM_WEBSITE_H

View file

@ -0,0 +1,46 @@
#include "dlg_load_remote_deck.h"
#include "../interface/widgets/server/remote/remote_decklist_tree_widget.h"
#include "../main.h"
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QPushButton>
#include <QVBoxLayout>
DlgLoadRemoteDeck::DlgLoadRemoteDeck(AbstractClient *_client, QWidget *parent) : QDialog(parent), client(_client)
{
dirView = new RemoteDeckList_TreeWidget(client);
dirView->refreshTree();
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgLoadRemoteDeck::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgLoadRemoteDeck::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(dirView);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Load deck"));
setMinimumWidth(sizeHint().width());
resize(400, 600);
connect(dirView->selectionModel(), &QItemSelectionModel::currentChanged, this,
&DlgLoadRemoteDeck::currentItemChanged);
}
void DlgLoadRemoteDeck::currentItemChanged(const QModelIndex &current, const QModelIndex & /*previous*/)
{
buttonBox->button(QDialogButtonBox::Ok)
->setEnabled(dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(dirView->getNode(current)));
}
int DlgLoadRemoteDeck::getDeckId() const
{
return dynamic_cast<RemoteDeckList_TreeModel::FileNode *>(
dirView->getNode(dirView->selectionModel()->currentIndex()))
->getId();
}

View file

@ -0,0 +1,34 @@
/**
* @file dlg_load_remote_deck.h
* @ingroup RemoteDeckStorageDialogs
* @ingroup Lobby
* @brief TODO: Document this.
*/
#ifndef DLG_STARTGAME_H
#define DLG_STARTGAME_H
#include <QDialog>
class RemoteDeckList_TreeWidget;
class QModelIndex;
class AbstractClient;
class QPushButton;
class QDialogButtonBox;
class DlgLoadRemoteDeck : public QDialog
{
Q_OBJECT
private:
AbstractClient *client;
RemoteDeckList_TreeWidget *dirView;
QDialogButtonBox *buttonBox;
private slots:
void currentItemChanged(const QModelIndex &current, const QModelIndex &previous);
public:
explicit DlgLoadRemoteDeck(AbstractClient *_client, QWidget *parent = nullptr);
int getDeckId() const;
};
#endif

View file

@ -0,0 +1,470 @@
#include "dlg_manage_sets.h"
#include "../interface/card_picture_loader/card_picture_loader.h"
#include "../interface/widgets/utility/custom_line_edit.h"
#include "../main.h"
#include <QAction>
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelection>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QToolBar>
#include <QTreeView>
#include <algorithm>
#include <libcockatrice/card/card_database/card_database_manager.h>
#include <libcockatrice/card/card_database/model/card_set/card_sets_model.h>
#include <libcockatrice/settings/cache_settings.h>
#define SORT_RESET -1
WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
{
setOrderIsSorted = false;
// left toolbar
setsEditToolBar = new QToolBar;
setsEditToolBar->setOrientation(Qt::Vertical);
setsEditToolBar->setIconSize(QSize(24, 24));
setsEditToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
aTop = new QAction(QString(), this);
aTop->setIcon(QPixmap("theme:icons/arrow_top_green"));
aTop->setToolTip(tr("Move selected set to the top"));
aTop->setEnabled(false);
connect(aTop, &QAction::triggered, this, &WndSets::actTop);
setsEditToolBar->addAction(aTop);
aUp = new QAction(QString(), this);
aUp->setIcon(QPixmap("theme:icons/arrow_up_green"));
aUp->setToolTip(tr("Move selected set up"));
aUp->setEnabled(false);
connect(aUp, &QAction::triggered, this, &WndSets::actUp);
setsEditToolBar->addAction(aUp);
aDown = new QAction(QString(), this);
aDown->setIcon(QPixmap("theme:icons/arrow_down_green"));
aDown->setToolTip(tr("Move selected set down"));
aDown->setEnabled(false);
connect(aDown, &QAction::triggered, this, &WndSets::actDown);
setsEditToolBar->addAction(aDown);
aBottom = new QAction(QString(), this);
aBottom->setIcon(QPixmap("theme:icons/arrow_bottom_green"));
aBottom->setToolTip(tr("Move selected set to the bottom"));
aBottom->setEnabled(false);
connect(aBottom, &QAction::triggered, this, &WndSets::actBottom);
setsEditToolBar->addAction(aBottom);
// search field
searchField = new LineEditUnfocusable;
searchField->setObjectName("searchEdit");
searchField->setPlaceholderText(tr("Search by set name, code, or type"));
searchField->addAction(QPixmap("theme:icons/search"), LineEditUnfocusable::LeadingPosition);
searchField->setClearButtonEnabled(true);
setFocusProxy(searchField);
defaultSortButton = new QPushButton(tr("Default order"));
defaultSortButton->setToolTip(tr("Restore original art priority order"));
connect(defaultSortButton, &QPushButton::clicked, this, &WndSets::actRestoreOriginalOrder);
filterBox = new QHBoxLayout;
filterBox->addWidget(searchField);
filterBox->addWidget(defaultSortButton);
// view
model = new SetsModel(CardDatabaseManager::getInstance(), this);
displayModel = new SetsDisplayModel(this);
displayModel->setSourceModel(model);
displayModel->setDynamicSortFilter(false);
view = new QTreeView;
view->setModel(displayModel);
view->setAlternatingRowColors(true);
view->setUniformRowHeights(true);
view->setAllColumnsShowFocus(true);
view->setSortingEnabled(true);
view->setSelectionBehavior(QAbstractItemView::SelectRows);
view->setSelectionMode(QAbstractItemView::ExtendedSelection);
view->setDragEnabled(true);
view->setAcceptDrops(true);
view->setDropIndicatorShown(true);
view->setDragDropMode(QAbstractItemView::InternalMove);
view->sortByColumn(SetsModel::SortKeyCol, Qt::AscendingOrder);
view->setColumnHidden(SetsModel::SortKeyCol, true);
view->setColumnHidden(SetsModel::IsKnownCol, true);
view->setColumnHidden(SetsModel::PriorityCol, true);
view->setRootIsDecorated(false);
connect(view->header(), &QHeaderView::sectionClicked, this, &WndSets::actSort);
// bottom buttons
enableAllButton = new QPushButton(tr("Enable all sets"));
disableAllButton = new QPushButton(tr("Disable all sets"));
enableSomeButton = new QPushButton(tr("Enable selected set(s)"));
disableSomeButton = new QPushButton(tr("Disable selected set(s)"));
connect(enableAllButton, &QPushButton::clicked, this, &WndSets::actEnableAll);
connect(disableAllButton, &QPushButton::clicked, this, &WndSets::actDisableAll);
connect(enableSomeButton, &QPushButton::clicked, this, &WndSets::actEnableSome);
connect(disableSomeButton, &QPushButton::clicked, this, &WndSets::actDisableSome);
connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, this, &WndSets::actToggleButtons);
connect(searchField, &LineEditUnfocusable::textChanged, displayModel,
qOverload<const QString &>(&SetsDisplayModel::setFilterRegularExpression));
connect(view->header(), &QHeaderView::sortIndicatorChanged, this, &WndSets::actDisableSortButtons);
connect(searchField, &LineEditUnfocusable::textChanged, this, &WndSets::actDisableResetButton);
labNotes = new QLabel;
labNotes->setWordWrap(true);
labNotes->setTextInteractionFlags(Qt::TextBrowserInteraction);
labNotes->setOpenExternalLinks(true);
labNotes->setText(tr("Use CTRL+A to select all sets in the view.") + "<br><b>" + tr("Deck Editor") + ":</b> " +
tr("Only cards in enabled sets will appear in the card list of the deck editor.") + "<br><b>" +
tr("Card Art") + ":</b> " + tr("Image priority is decided in the following order:") + "<br>" +
tr("first the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)",
"%1 is a link to the wiki")
.arg("<a href='https://github.com/Cockatrice/Cockatrice/wiki/Custom-Cards-%26-Sets"
"#to-add-custom-art-for-cards-the-easiest-way-is-to-use-the-custom-folder'>" +
tr("How to use custom card art") + "</a>"));
QGridLayout *hintsGrid = new QGridLayout;
hintsGrid->addWidget(labNotes, 0, 0);
hintsGroupBox = new QGroupBox(tr("Hints"));
hintsGroupBox->setLayout(hintsGrid);
sortWarning = new QGroupBox(tr("Note"));
QGridLayout *sortWarningLayout = new QGridLayout;
sortWarningText = new QLabel;
sortWarningText->setWordWrap(true);
sortWarningText->setText(tr("Sorting by column allows you to find a set while not changing set priority.") + " " +
tr("To enable ordering again, click the column header until this message disappears."));
sortWarningLayout->addWidget(sortWarningText, 0, 0, 1, 2);
sortWarningButton = new QPushButton;
sortWarningButton->setText(tr("Use the current sorting as the set priority instead"));
sortWarningButton->setToolTip(tr("Sorts the set priority using the same column"));
sortWarningButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(sortWarningButton, &QPushButton::released, this, &WndSets::actIgnoreWarning);
sortWarningLayout->addWidget(sortWarningButton, 1, 0);
sortWarning->setLayout(sortWarningLayout);
sortWarning->setVisible(false);
includeRebalancedCards = SettingsCache::instance().getIncludeRebalancedCards();
QCheckBox *includeRebalancedCardsCheckBox =
new QCheckBox(tr("Include cards rebalanced for Alchemy [requires restart]"));
includeRebalancedCardsCheckBox->setChecked(includeRebalancedCards);
connect(includeRebalancedCardsCheckBox, &QAbstractButton::toggled, this, &WndSets::includeRebalancedCardsChanged);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &WndSets::actSave);
connect(buttonBox, &QDialogButtonBox::rejected, this, &WndSets::actRestore);
mainLayout = new QGridLayout;
mainLayout->addLayout(filterBox, 0, 1, 1, 2);
mainLayout->addWidget(setsEditToolBar, 1, 0, 4, 1);
mainLayout->addWidget(view, 1, 1, 1, 2);
mainLayout->addWidget(enableAllButton, 2, 1);
mainLayout->addWidget(disableAllButton, 2, 2);
mainLayout->addWidget(enableSomeButton, 2, 1);
mainLayout->addWidget(disableSomeButton, 2, 2);
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
mainLayout->addWidget(includeRebalancedCardsCheckBox, 4, 1, 1, 2);
mainLayout->addWidget(hintsGroupBox, 5, 1, 1, 2);
mainLayout->addWidget(buttonBox, 6, 1, 1, 2);
mainLayout->setColumnStretch(1, 1);
mainLayout->setColumnStretch(2, 1);
enableSomeButton->hide();
disableSomeButton->hide();
QWidget *centralWidget = new QWidget;
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
setWindowTitle(tr("Manage sets"));
setMinimumSize(800, 500);
auto &geometry = SettingsCache::instance().getSetsDialogGeometry();
if (!geometry.isEmpty()) {
restoreGeometry(geometry);
}
auto &headerState = SettingsCache::instance().layouts().getSetsDialogHeaderState();
if (!headerState.isEmpty()) {
view->header()->restoreState(headerState);
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
} else {
view->header()->resizeSections(QHeaderView::ResizeToContents);
}
connect(view->header(), &QHeaderView::geometriesChanged, this, &WndSets::saveHeaderState);
}
WndSets::~WndSets()
{
}
void WndSets::closeEvent(QCloseEvent * /*ev*/)
{
SettingsCache::instance().setSetsDialogGeometry(saveGeometry());
}
void WndSets::saveHeaderState()
{
SettingsCache::instance().layouts().setSetsDialogHeaderState(view->header()->saveState());
}
void WndSets::rebuildMainLayout(int actionToTake)
{
if (mainLayout == nullptr)
return;
switch (actionToTake) {
case NO_SETS_SELECTED:
enableAllButton->show();
disableAllButton->show();
enableSomeButton->hide();
disableSomeButton->hide();
break;
case SOME_SETS_SELECTED:
enableAllButton->hide();
disableAllButton->hide();
enableSomeButton->show();
disableSomeButton->show();
break;
}
}
void WndSets::includeRebalancedCardsChanged(bool _includeRebalancedCards)
{
includeRebalancedCards = _includeRebalancedCards;
}
void WndSets::actSave()
{
model->save(CardDatabaseManager::getInstance());
SettingsCache::instance().setIncludeRebalancedCards(includeRebalancedCards);
CardPictureLoader::clearPixmapCache();
close();
}
void WndSets::actRestore()
{
model->restore(CardDatabaseManager::getInstance());
close();
}
void WndSets::actRestoreOriginalOrder()
{
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
model->restoreOriginalOrder();
sortWarning->setVisible(false);
}
void WndSets::actDisableResetButton(const QString &filterString)
{
if (filterString.isEmpty()) {
defaultSortButton->setEnabled(true);
} else {
defaultSortButton->setEnabled(false);
}
}
void WndSets::actSort(int index)
{
if (sortIndex != index) {
view->sortByColumn(index, Qt::AscendingOrder);
sortOrder = Qt::AscendingOrder;
sortIndex = index;
sortWarning->setVisible(true);
} else {
if (sortOrder == Qt::AscendingOrder) {
view->sortByColumn(index, Qt::DescendingOrder);
sortOrder = Qt::DescendingOrder;
sortIndex = index;
sortWarning->setVisible(true);
} else {
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
sortIndex = -1;
sortWarning->setVisible(false);
}
}
}
void WndSets::actIgnoreWarning()
{
if (sortIndex < 0) {
return;
}
model->sort(sortIndex, sortOrder);
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
sortIndex = -1;
sortWarning->setVisible(false);
}
void WndSets::actDisableSortButtons(int index)
{
if (index != SORT_RESET) {
view->setDragEnabled(false);
setOrderIsSorted = true;
} else {
setOrderIsSorted = false;
view->setDragEnabled(true);
}
if (!view->selectionModel()->selection().empty()) {
view->scrollTo(view->selectionModel()->selectedRows().first());
}
actToggleButtons(view->selectionModel()->selection(), QItemSelection());
}
void WndSets::actToggleButtons(const QItemSelection &selected, const QItemSelection &)
{
bool emptySelection = selected.empty();
aTop->setDisabled(emptySelection || setOrderIsSorted);
aUp->setDisabled(emptySelection || setOrderIsSorted);
aDown->setDisabled(emptySelection || setOrderIsSorted);
aBottom->setDisabled(emptySelection || setOrderIsSorted);
int rows = view->selectionModel()->selectedRows().size();
rebuildMainLayout((rows > 1) ? SOME_SETS_SELECTED : NO_SETS_SELECTED);
}
void WndSets::selectRows(QSet<int> rows)
{
for (auto i : rows) {
QModelIndex idx = model->index(i, 0);
view->selectionModel()->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
view->scrollTo(idx, QAbstractItemView::EnsureVisible);
}
}
void WndSets::actEnableAll()
{
model->toggleAll(true);
}
void WndSets::actDisableAll()
{
model->toggleAll(false);
}
void WndSets::actEnableSome()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
for (auto i : rows) {
model->toggleRow(displayModel->mapToSource(i).row(), true);
}
}
void WndSets::actDisableSome()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
for (auto i : rows) {
model->toggleRow(displayModel->mapToSource(i).row(), false);
}
}
void WndSets::actUp()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
std::sort(rows.begin(), rows.end(), std::less<QModelIndex>());
QSet<int> newRows;
if (rows.empty())
return;
for (auto i : rows) {
if (i.row() <= 0)
continue;
int oldRow = displayModel->mapToSource(i).row();
int newRow = i.row() - 1;
model->swapRows(oldRow, displayModel->mapToSource(displayModel->index(newRow, 0)).row());
newRows.insert(newRow);
}
selectRows(newRows);
}
void WndSets::actDown()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
// QModelIndex only implements operator<, so we can't use std::greater
std::sort(rows.begin(), rows.end(), [](const QModelIndex &a, const QModelIndex &b) { return b < a; });
QSet<int> newRows;
if (rows.empty())
return;
for (auto i : rows) {
if (i.row() >= displayModel->rowCount() - 1)
continue;
int oldRow = displayModel->mapToSource(i).row();
int newRow = i.row() + 1;
model->swapRows(oldRow, displayModel->mapToSource(displayModel->index(newRow, 0)).row());
newRows.insert(newRow);
}
selectRows(newRows);
}
void WndSets::actTop()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
std::sort(rows.begin(), rows.end(), std::less<QModelIndex>());
QSet<int> newRows;
int newRow = 0;
if (rows.empty())
return;
for (int i = 0; i < rows.length(); i++) {
int oldRow = displayModel->mapToSource(rows.at(i)).row();
if (oldRow <= 0) {
newRow++;
continue;
}
newRows.insert(newRow);
model->swapRows(oldRow, newRow++);
}
selectRows(newRows);
}
void WndSets::actBottom()
{
QModelIndexList rows = view->selectionModel()->selectedRows();
// QModelIndex only implements operator<, so we can't use std::greater
std::sort(rows.begin(), rows.end(), [](const QModelIndex &a, const QModelIndex &b) { return b < a; });
QSet<int> newRows;
int newRow = model->rowCount() - 1;
if (rows.empty())
return;
for (int i = 0; i < rows.length(); i++) {
int oldRow = displayModel->mapToSource(rows.at(i)).row();
if (oldRow >= newRow) {
newRow--;
continue;
}
newRows.insert(newRow);
model->swapRows(oldRow, newRow--);
}
selectRows(newRows);
}

View file

@ -0,0 +1,86 @@
/**
* @file dlg_manage_sets.h
* @ingroup Dialogs
* @brief TODO: Document this.
*/
#ifndef DLG_MANAGE_SETS_H
#define DLG_MANAGE_SETS_H
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QMainWindow>
#include <QSet>
class CardDatabase;
class LineEditUnfocusable;
class QGroupBox;
class QItemSelection;
class QPushButton;
class QTreeView;
class SetsDisplayModel;
class SetsModel;
class SetsProxyModel;
class WndSets : public QMainWindow
{
Q_OBJECT
private:
SetsModel *model;
SetsDisplayModel *displayModel;
QGroupBox *hintsGroupBox;
QTreeView *view;
QPushButton *toggleAllButton, *toggleSelectedButton;
QPushButton *enableAllButton, *disableAllButton, *enableSomeButton, *disableSomeButton;
QPushButton *defaultSortButton;
QAction *aUp, *aDown, *aBottom, *aTop;
QToolBar *setsEditToolBar;
QDialogButtonBox *buttonBox;
QLabel *labNotes, *searchLabel;
QGroupBox *sortWarning;
QLabel *sortWarningText;
QPushButton *sortWarningButton;
LineEditUnfocusable *searchField;
QGridLayout *mainLayout;
QHBoxLayout *filterBox;
int sortIndex;
Qt::SortOrder sortOrder;
void closeEvent(QCloseEvent *ev) override;
void saveHeaderState();
void rebuildMainLayout(int actionToTake);
bool setOrderIsSorted;
bool includeRebalancedCards;
enum
{
NO_SETS_SELECTED,
SOME_SETS_SELECTED
};
public:
explicit WndSets(QWidget *parent = nullptr);
~WndSets() override;
protected:
void selectRows(QSet<int> rows);
private slots:
void actEnableAll();
void actDisableAll();
void actEnableSome();
void actDisableSome();
void actSave();
void actRestore();
void actUp();
void actDown();
void actTop();
void actBottom();
void actToggleButtons(const QItemSelection &selected, const QItemSelection &deselected);
void actDisableSortButtons(int index);
void actRestoreOriginalOrder();
void actDisableResetButton(const QString &filterText);
void actSort(int index);
void actIgnoreWarning();
void includeRebalancedCardsChanged(bool _includeRebalancedCardsChanged);
};
#endif

View file

@ -0,0 +1,378 @@
#include "dlg_register.h"
#include <QCheckBox>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/trice_limits.h>
DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
{
ServersSettings &servers = SettingsCache::instance().servers();
infoLabel = new QLabel(tr("Enter your information and the information of the server you'd like to register to.\n"
"Your email will be used to verify your account."));
infoLabel->setWordWrap(true);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(servers.getHostname());
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(servers.getPort());
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(servers.getPlayerName());
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
passwordLabel = new QLabel(tr("P&assword:"));
passwordEdit = new QLineEdit();
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
passwordEdit->setEchoMode(QLineEdit::Password);
passwordConfirmationLabel = new QLabel(tr("Password (again):"));
passwordConfirmationEdit = new QLineEdit();
passwordConfirmationEdit->setMaxLength(MAX_NAME_LENGTH);
passwordConfirmationLabel->setBuddy(passwordConfirmationEdit);
passwordConfirmationEdit->setEchoMode(QLineEdit::Password);
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailEdit);
emailConfirmationLabel = new QLabel(tr("Email (again):"));
emailConfirmationEdit = new QLineEdit();
emailConfirmationEdit->setMaxLength(MAX_NAME_LENGTH);
emailConfirmationLabel->setBuddy(emailConfirmationEdit);
countryLabel = new QLabel(tr("Country:"));
countryEdit = new QComboBox();
countryLabel->setBuddy(countryEdit);
countryEdit->insertItem(0, tr("Undefined"));
countryEdit->addItem(QPixmap("theme:countries/ad"), "ad");
countryEdit->addItem(QPixmap("theme:countries/ae"), "ae");
countryEdit->addItem(QPixmap("theme:countries/af"), "af");
countryEdit->addItem(QPixmap("theme:countries/ag"), "ag");
countryEdit->addItem(QPixmap("theme:countries/ai"), "ai");
countryEdit->addItem(QPixmap("theme:countries/al"), "al");
countryEdit->addItem(QPixmap("theme:countries/am"), "am");
countryEdit->addItem(QPixmap("theme:countries/ao"), "ao");
countryEdit->addItem(QPixmap("theme:countries/aq"), "aq");
countryEdit->addItem(QPixmap("theme:countries/ar"), "ar");
countryEdit->addItem(QPixmap("theme:countries/as"), "as");
countryEdit->addItem(QPixmap("theme:countries/at"), "at");
countryEdit->addItem(QPixmap("theme:countries/au"), "au");
countryEdit->addItem(QPixmap("theme:countries/aw"), "aw");
countryEdit->addItem(QPixmap("theme:countries/ax"), "ax");
countryEdit->addItem(QPixmap("theme:countries/az"), "az");
countryEdit->addItem(QPixmap("theme:countries/ba"), "ba");
countryEdit->addItem(QPixmap("theme:countries/bb"), "bb");
countryEdit->addItem(QPixmap("theme:countries/bd"), "bd");
countryEdit->addItem(QPixmap("theme:countries/be"), "be");
countryEdit->addItem(QPixmap("theme:countries/bf"), "bf");
countryEdit->addItem(QPixmap("theme:countries/bg"), "bg");
countryEdit->addItem(QPixmap("theme:countries/bh"), "bh");
countryEdit->addItem(QPixmap("theme:countries/bi"), "bi");
countryEdit->addItem(QPixmap("theme:countries/bj"), "bj");
countryEdit->addItem(QPixmap("theme:countries/bl"), "bl");
countryEdit->addItem(QPixmap("theme:countries/bm"), "bm");
countryEdit->addItem(QPixmap("theme:countries/bn"), "bn");
countryEdit->addItem(QPixmap("theme:countries/bo"), "bo");
countryEdit->addItem(QPixmap("theme:countries/bq"), "bq");
countryEdit->addItem(QPixmap("theme:countries/br"), "br");
countryEdit->addItem(QPixmap("theme:countries/bs"), "bs");
countryEdit->addItem(QPixmap("theme:countries/bt"), "bt");
countryEdit->addItem(QPixmap("theme:countries/bv"), "bv");
countryEdit->addItem(QPixmap("theme:countries/bw"), "bw");
countryEdit->addItem(QPixmap("theme:countries/by"), "by");
countryEdit->addItem(QPixmap("theme:countries/bz"), "bz");
countryEdit->addItem(QPixmap("theme:countries/ca"), "ca");
countryEdit->addItem(QPixmap("theme:countries/cc"), "cc");
countryEdit->addItem(QPixmap("theme:countries/cd"), "cd");
countryEdit->addItem(QPixmap("theme:countries/cf"), "cf");
countryEdit->addItem(QPixmap("theme:countries/cg"), "cg");
countryEdit->addItem(QPixmap("theme:countries/ch"), "ch");
countryEdit->addItem(QPixmap("theme:countries/ci"), "ci");
countryEdit->addItem(QPixmap("theme:countries/ck"), "ck");
countryEdit->addItem(QPixmap("theme:countries/cl"), "cl");
countryEdit->addItem(QPixmap("theme:countries/cm"), "cm");
countryEdit->addItem(QPixmap("theme:countries/cn"), "cn");
countryEdit->addItem(QPixmap("theme:countries/co"), "co");
countryEdit->addItem(QPixmap("theme:countries/cr"), "cr");
countryEdit->addItem(QPixmap("theme:countries/cu"), "cu");
countryEdit->addItem(QPixmap("theme:countries/cv"), "cv");
countryEdit->addItem(QPixmap("theme:countries/cw"), "cw");
countryEdit->addItem(QPixmap("theme:countries/cx"), "cx");
countryEdit->addItem(QPixmap("theme:countries/cy"), "cy");
countryEdit->addItem(QPixmap("theme:countries/cz"), "cz");
countryEdit->addItem(QPixmap("theme:countries/de"), "de");
countryEdit->addItem(QPixmap("theme:countries/dj"), "dj");
countryEdit->addItem(QPixmap("theme:countries/dk"), "dk");
countryEdit->addItem(QPixmap("theme:countries/dm"), "dm");
countryEdit->addItem(QPixmap("theme:countries/do"), "do");
countryEdit->addItem(QPixmap("theme:countries/dz"), "dz");
countryEdit->addItem(QPixmap("theme:countries/ec"), "ec");
countryEdit->addItem(QPixmap("theme:countries/ee"), "ee");
countryEdit->addItem(QPixmap("theme:countries/eg"), "eg");
countryEdit->addItem(QPixmap("theme:countries/eh"), "eh");
countryEdit->addItem(QPixmap("theme:countries/er"), "er");
countryEdit->addItem(QPixmap("theme:countries/es"), "es");
countryEdit->addItem(QPixmap("theme:countries/et"), "et");
countryEdit->addItem(QPixmap("theme:countries/eu"), "eu");
countryEdit->addItem(QPixmap("theme:countries/fi"), "fi");
countryEdit->addItem(QPixmap("theme:countries/fj"), "fj");
countryEdit->addItem(QPixmap("theme:countries/fk"), "fk");
countryEdit->addItem(QPixmap("theme:countries/fm"), "fm");
countryEdit->addItem(QPixmap("theme:countries/fo"), "fo");
countryEdit->addItem(QPixmap("theme:countries/fr"), "fr");
countryEdit->addItem(QPixmap("theme:countries/ga"), "ga");
countryEdit->addItem(QPixmap("theme:countries/gb"), "gb");
countryEdit->addItem(QPixmap("theme:countries/gd"), "gd");
countryEdit->addItem(QPixmap("theme:countries/ge"), "ge");
countryEdit->addItem(QPixmap("theme:countries/gf"), "gf");
countryEdit->addItem(QPixmap("theme:countries/gg"), "gg");
countryEdit->addItem(QPixmap("theme:countries/gh"), "gh");
countryEdit->addItem(QPixmap("theme:countries/gi"), "gi");
countryEdit->addItem(QPixmap("theme:countries/gl"), "gl");
countryEdit->addItem(QPixmap("theme:countries/gm"), "gm");
countryEdit->addItem(QPixmap("theme:countries/gn"), "gn");
countryEdit->addItem(QPixmap("theme:countries/gp"), "gp");
countryEdit->addItem(QPixmap("theme:countries/gq"), "gq");
countryEdit->addItem(QPixmap("theme:countries/gr"), "gr");
countryEdit->addItem(QPixmap("theme:countries/gs"), "gs");
countryEdit->addItem(QPixmap("theme:countries/gt"), "gt");
countryEdit->addItem(QPixmap("theme:countries/gu"), "gu");
countryEdit->addItem(QPixmap("theme:countries/gw"), "gw");
countryEdit->addItem(QPixmap("theme:countries/gy"), "gy");
countryEdit->addItem(QPixmap("theme:countries/hk"), "hk");
countryEdit->addItem(QPixmap("theme:countries/hm"), "hm");
countryEdit->addItem(QPixmap("theme:countries/hn"), "hn");
countryEdit->addItem(QPixmap("theme:countries/hr"), "hr");
countryEdit->addItem(QPixmap("theme:countries/ht"), "ht");
countryEdit->addItem(QPixmap("theme:countries/hu"), "hu");
countryEdit->addItem(QPixmap("theme:countries/id"), "id");
countryEdit->addItem(QPixmap("theme:countries/ie"), "ie");
countryEdit->addItem(QPixmap("theme:countries/il"), "il");
countryEdit->addItem(QPixmap("theme:countries/im"), "im");
countryEdit->addItem(QPixmap("theme:countries/in"), "in");
countryEdit->addItem(QPixmap("theme:countries/io"), "io");
countryEdit->addItem(QPixmap("theme:countries/iq"), "iq");
countryEdit->addItem(QPixmap("theme:countries/ir"), "ir");
countryEdit->addItem(QPixmap("theme:countries/is"), "is");
countryEdit->addItem(QPixmap("theme:countries/it"), "it");
countryEdit->addItem(QPixmap("theme:countries/je"), "je");
countryEdit->addItem(QPixmap("theme:countries/jm"), "jm");
countryEdit->addItem(QPixmap("theme:countries/jo"), "jo");
countryEdit->addItem(QPixmap("theme:countries/jp"), "jp");
countryEdit->addItem(QPixmap("theme:countries/ke"), "ke");
countryEdit->addItem(QPixmap("theme:countries/kg"), "kg");
countryEdit->addItem(QPixmap("theme:countries/kh"), "kh");
countryEdit->addItem(QPixmap("theme:countries/ki"), "ki");
countryEdit->addItem(QPixmap("theme:countries/km"), "km");
countryEdit->addItem(QPixmap("theme:countries/kn"), "kn");
countryEdit->addItem(QPixmap("theme:countries/kp"), "kp");
countryEdit->addItem(QPixmap("theme:countries/kr"), "kr");
countryEdit->addItem(QPixmap("theme:countries/kw"), "kw");
countryEdit->addItem(QPixmap("theme:countries/ky"), "ky");
countryEdit->addItem(QPixmap("theme:countries/kz"), "kz");
countryEdit->addItem(QPixmap("theme:countries/la"), "la");
countryEdit->addItem(QPixmap("theme:countries/lb"), "lb");
countryEdit->addItem(QPixmap("theme:countries/lc"), "lc");
countryEdit->addItem(QPixmap("theme:countries/li"), "li");
countryEdit->addItem(QPixmap("theme:countries/lk"), "lk");
countryEdit->addItem(QPixmap("theme:countries/lr"), "lr");
countryEdit->addItem(QPixmap("theme:countries/ls"), "ls");
countryEdit->addItem(QPixmap("theme:countries/lt"), "lt");
countryEdit->addItem(QPixmap("theme:countries/lu"), "lu");
countryEdit->addItem(QPixmap("theme:countries/lv"), "lv");
countryEdit->addItem(QPixmap("theme:countries/ly"), "ly");
countryEdit->addItem(QPixmap("theme:countries/ma"), "ma");
countryEdit->addItem(QPixmap("theme:countries/mc"), "mc");
countryEdit->addItem(QPixmap("theme:countries/md"), "md");
countryEdit->addItem(QPixmap("theme:countries/me"), "me");
countryEdit->addItem(QPixmap("theme:countries/mf"), "mf");
countryEdit->addItem(QPixmap("theme:countries/mg"), "mg");
countryEdit->addItem(QPixmap("theme:countries/mh"), "mh");
countryEdit->addItem(QPixmap("theme:countries/mk"), "mk");
countryEdit->addItem(QPixmap("theme:countries/ml"), "ml");
countryEdit->addItem(QPixmap("theme:countries/mm"), "mm");
countryEdit->addItem(QPixmap("theme:countries/mn"), "mn");
countryEdit->addItem(QPixmap("theme:countries/mo"), "mo");
countryEdit->addItem(QPixmap("theme:countries/mp"), "mp");
countryEdit->addItem(QPixmap("theme:countries/mq"), "mq");
countryEdit->addItem(QPixmap("theme:countries/mr"), "mr");
countryEdit->addItem(QPixmap("theme:countries/ms"), "ms");
countryEdit->addItem(QPixmap("theme:countries/mt"), "mt");
countryEdit->addItem(QPixmap("theme:countries/mu"), "mu");
countryEdit->addItem(QPixmap("theme:countries/mv"), "mv");
countryEdit->addItem(QPixmap("theme:countries/mw"), "mw");
countryEdit->addItem(QPixmap("theme:countries/mx"), "mx");
countryEdit->addItem(QPixmap("theme:countries/my"), "my");
countryEdit->addItem(QPixmap("theme:countries/mz"), "mz");
countryEdit->addItem(QPixmap("theme:countries/na"), "na");
countryEdit->addItem(QPixmap("theme:countries/nc"), "nc");
countryEdit->addItem(QPixmap("theme:countries/ne"), "ne");
countryEdit->addItem(QPixmap("theme:countries/nf"), "nf");
countryEdit->addItem(QPixmap("theme:countries/ng"), "ng");
countryEdit->addItem(QPixmap("theme:countries/ni"), "ni");
countryEdit->addItem(QPixmap("theme:countries/nl"), "nl");
countryEdit->addItem(QPixmap("theme:countries/no"), "no");
countryEdit->addItem(QPixmap("theme:countries/np"), "np");
countryEdit->addItem(QPixmap("theme:countries/nr"), "nr");
countryEdit->addItem(QPixmap("theme:countries/nu"), "nu");
countryEdit->addItem(QPixmap("theme:countries/nz"), "nz");
countryEdit->addItem(QPixmap("theme:countries/om"), "om");
countryEdit->addItem(QPixmap("theme:countries/pa"), "pa");
countryEdit->addItem(QPixmap("theme:countries/pe"), "pe");
countryEdit->addItem(QPixmap("theme:countries/pf"), "pf");
countryEdit->addItem(QPixmap("theme:countries/pg"), "pg");
countryEdit->addItem(QPixmap("theme:countries/ph"), "ph");
countryEdit->addItem(QPixmap("theme:countries/pk"), "pk");
countryEdit->addItem(QPixmap("theme:countries/pl"), "pl");
countryEdit->addItem(QPixmap("theme:countries/pm"), "pm");
countryEdit->addItem(QPixmap("theme:countries/pn"), "pn");
countryEdit->addItem(QPixmap("theme:countries/pr"), "pr");
countryEdit->addItem(QPixmap("theme:countries/ps"), "ps");
countryEdit->addItem(QPixmap("theme:countries/pt"), "pt");
countryEdit->addItem(QPixmap("theme:countries/pw"), "pw");
countryEdit->addItem(QPixmap("theme:countries/py"), "py");
countryEdit->addItem(QPixmap("theme:countries/qa"), "qa");
countryEdit->addItem(QPixmap("theme:countries/re"), "re");
countryEdit->addItem(QPixmap("theme:countries/ro"), "ro");
countryEdit->addItem(QPixmap("theme:countries/rs"), "rs");
countryEdit->addItem(QPixmap("theme:countries/ru"), "ru");
countryEdit->addItem(QPixmap("theme:countries/rw"), "rw");
countryEdit->addItem(QPixmap("theme:countries/sa"), "sa");
countryEdit->addItem(QPixmap("theme:countries/sb"), "sb");
countryEdit->addItem(QPixmap("theme:countries/sc"), "sc");
countryEdit->addItem(QPixmap("theme:countries/sd"), "sd");
countryEdit->addItem(QPixmap("theme:countries/se"), "se");
countryEdit->addItem(QPixmap("theme:countries/sg"), "sg");
countryEdit->addItem(QPixmap("theme:countries/sh"), "sh");
countryEdit->addItem(QPixmap("theme:countries/si"), "si");
countryEdit->addItem(QPixmap("theme:countries/sj"), "sj");
countryEdit->addItem(QPixmap("theme:countries/sk"), "sk");
countryEdit->addItem(QPixmap("theme:countries/sl"), "sl");
countryEdit->addItem(QPixmap("theme:countries/sm"), "sm");
countryEdit->addItem(QPixmap("theme:countries/sn"), "sn");
countryEdit->addItem(QPixmap("theme:countries/so"), "so");
countryEdit->addItem(QPixmap("theme:countries/sr"), "sr");
countryEdit->addItem(QPixmap("theme:countries/ss"), "ss");
countryEdit->addItem(QPixmap("theme:countries/st"), "st");
countryEdit->addItem(QPixmap("theme:countries/sv"), "sv");
countryEdit->addItem(QPixmap("theme:countries/sx"), "sx");
countryEdit->addItem(QPixmap("theme:countries/sy"), "sy");
countryEdit->addItem(QPixmap("theme:countries/sz"), "sz");
countryEdit->addItem(QPixmap("theme:countries/tc"), "tc");
countryEdit->addItem(QPixmap("theme:countries/td"), "td");
countryEdit->addItem(QPixmap("theme:countries/tf"), "tf");
countryEdit->addItem(QPixmap("theme:countries/tg"), "tg");
countryEdit->addItem(QPixmap("theme:countries/th"), "th");
countryEdit->addItem(QPixmap("theme:countries/tj"), "tj");
countryEdit->addItem(QPixmap("theme:countries/tk"), "tk");
countryEdit->addItem(QPixmap("theme:countries/tl"), "tl");
countryEdit->addItem(QPixmap("theme:countries/tm"), "tm");
countryEdit->addItem(QPixmap("theme:countries/tn"), "tn");
countryEdit->addItem(QPixmap("theme:countries/to"), "to");
countryEdit->addItem(QPixmap("theme:countries/tr"), "tr");
countryEdit->addItem(QPixmap("theme:countries/tt"), "tt");
countryEdit->addItem(QPixmap("theme:countries/tv"), "tv");
countryEdit->addItem(QPixmap("theme:countries/tw"), "tw");
countryEdit->addItem(QPixmap("theme:countries/tz"), "tz");
countryEdit->addItem(QPixmap("theme:countries/ua"), "ua");
countryEdit->addItem(QPixmap("theme:countries/ug"), "ug");
countryEdit->addItem(QPixmap("theme:countries/um"), "um");
countryEdit->addItem(QPixmap("theme:countries/us"), "us");
countryEdit->addItem(QPixmap("theme:countries/uy"), "uy");
countryEdit->addItem(QPixmap("theme:countries/uz"), "uz");
countryEdit->addItem(QPixmap("theme:countries/va"), "va");
countryEdit->addItem(QPixmap("theme:countries/vc"), "vc");
countryEdit->addItem(QPixmap("theme:countries/ve"), "ve");
countryEdit->addItem(QPixmap("theme:countries/vg"), "vg");
countryEdit->addItem(QPixmap("theme:countries/vi"), "vi");
countryEdit->addItem(QPixmap("theme:countries/vn"), "vn");
countryEdit->addItem(QPixmap("theme:countries/vu"), "vu");
countryEdit->addItem(QPixmap("theme:countries/wf"), "wf");
countryEdit->addItem(QPixmap("theme:countries/ws"), "ws");
countryEdit->addItem(QPixmap("theme:countries/xk"), "xk");
countryEdit->addItem(QPixmap("theme:countries/ye"), "ye");
countryEdit->addItem(QPixmap("theme:countries/yt"), "yt");
countryEdit->addItem(QPixmap("theme:countries/za"), "za");
countryEdit->addItem(QPixmap("theme:countries/zm"), "zm");
countryEdit->addItem(QPixmap("theme:countries/zw"), "zw");
countryEdit->setCurrentIndex(0);
QStringList countries = SettingsCache::instance().getCountries();
for (const QString &c : countries)
countryEdit->addItem(QPixmap("theme:countries/" + c.toLower()), c);
realnameLabel = new QLabel(tr("Real name:"));
realnameEdit = new QLineEdit();
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
realnameLabel->setBuddy(realnameEdit);
QGridLayout *grid = new QGridLayout;
grid->addWidget(infoLabel, 0, 0, 1, 2);
grid->addWidget(hostLabel, 1, 0);
grid->addWidget(hostEdit, 1, 1);
grid->addWidget(portLabel, 2, 0);
grid->addWidget(portEdit, 2, 1);
grid->addWidget(playernameLabel, 3, 0);
grid->addWidget(playernameEdit, 3, 1);
grid->addWidget(passwordLabel, 4, 0);
grid->addWidget(passwordEdit, 4, 1);
grid->addWidget(passwordConfirmationLabel, 5, 0);
grid->addWidget(passwordConfirmationEdit, 5, 1);
grid->addWidget(emailLabel, 6, 0);
grid->addWidget(emailEdit, 6, 1);
grid->addWidget(emailConfirmationLabel, 7, 0);
grid->addWidget(emailConfirmationEdit, 7, 1);
grid->addWidget(countryLabel, 9, 0);
grid->addWidget(countryEdit, 9, 1);
grid->addWidget(realnameLabel, 10, 0);
grid->addWidget(realnameEdit, 10, 1);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DlgRegister::actOk);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DlgRegister::reject);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(grid);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setWindowTitle(tr("Register to server"));
setFixedHeight(sizeHint().height());
setMinimumWidth(300);
}
void DlgRegister::actOk()
{
// TODO this stuff should be using qvalidators
if (passwordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Registration Warning"), tr("Your password is too short."));
return;
} else if (passwordEdit->text() != passwordConfirmationEdit->text()) {
QMessageBox::critical(this, tr("Registration Warning"), tr("Your passwords do not match, please try again."));
return;
} else if (emailConfirmationEdit->text() != emailEdit->text()) {
QMessageBox::critical(this, tr("Registration Warning"),
tr("Your email addresses do not match, please try again."));
return;
}
if (playernameEdit->text().isEmpty()) {
QMessageBox::critical(this, tr("Registration Warning"), tr("The player name can't be empty."));
return;
}
accept();
}

View file

@ -0,0 +1,62 @@
/**
* @file dlg_register.h
* @ingroup AccountDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_REGISTER_H
#define DLG_REGISTER_H
#include <QComboBox>
#include <QDialog>
#include <QLineEdit>
class QLabel;
class QPushButton;
class QCheckBox;
class DlgRegister : public QDialog
{
Q_OBJECT
public:
explicit DlgRegister(QWidget *parent = nullptr);
QString getHost() const
{
return hostEdit->text();
}
int getPort() const
{
return portEdit->text().toInt();
}
QString getPlayerName() const
{
return playernameEdit->text();
}
QString getPassword() const
{
return passwordEdit->text();
}
QString getEmail() const
{
return emailEdit->text();
}
QString getCountry() const
{
return countryEdit->currentIndex() == 0 ? "" : countryEdit->currentText();
}
QString getRealName() const
{
return realnameEdit->text();
}
private slots:
void actOk();
private:
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *passwordConfirmationLabel,
*emailLabel, *emailConfirmationLabel, *countryLabel, *realnameLabel;
QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *passwordConfirmationEdit, *emailEdit,
*emailConfirmationEdit, *realnameEdit;
QComboBox *countryEdit;
};
#endif

View file

@ -0,0 +1,642 @@
#include "dlg_select_set_for_cards.h"
#include "../interface/widgets/cards/card_info_picture_widget.h"
#include "../interface/widgets/general/layout_containers/flow_widget.h"
#include "dlg_select_set_for_cards.h"
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QLabel>
#include <QMessageBox>
#include <QMimeData>
#include <QPainter>
#include <QPushButton>
#include <QScrollBar>
#include <QSplitter>
#include <QVBoxLayout>
#include <algorithm>
#include <libcockatrice/card/card_database/card_database_manager.h>
#include <libcockatrice/deck_list/deck_loader.h>
#include <qdrag.h>
#include <qevent.h>
DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_model) : QDialog(parent), model(_model)
{
setMinimumSize(500, 500);
setAcceptDrops(true);
instructionLabel = new QLabel(this);
instructionLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
setLayout(mainLayout);
// Main vertical splitter
QSplitter *splitter = new QSplitter(Qt::Vertical, this);
// Top scroll area
scrollArea = new QScrollArea(this);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
scrollArea->setWidgetResizable(true);
listContainer = new QWidget(scrollArea);
listLayout = new QVBoxLayout(listContainer);
listContainer->setLayout(listLayout);
scrollArea->setWidget(listContainer);
// Bottom horizontal splitter
QSplitter *bottomSplitter = new QSplitter(Qt::Horizontal, this);
// Left container
QWidget *leftContainer = new QWidget(this);
QVBoxLayout *leftLayout = new QVBoxLayout(leftContainer);
leftLayout->setContentsMargins(0, 0, 0, 0);
uneditedCardsLabel = new QLabel(this);
uneditedCardsArea = new QScrollArea(this);
uneditedCardsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
uneditedCardsArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
uneditedCardsArea->setWidgetResizable(true);
uneditedCardsFlowWidget =
new FlowWidget(uneditedCardsArea, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
uneditedCardsArea->setWidget(uneditedCardsFlowWidget);
leftLayout->addWidget(uneditedCardsLabel);
leftLayout->addWidget(uneditedCardsArea);
leftContainer->setLayout(leftLayout);
// Right container
QWidget *rightContainer = new QWidget(this);
QVBoxLayout *rightLayout = new QVBoxLayout(rightContainer);
rightLayout->setContentsMargins(0, 0, 0, 0);
modifiedCardsLabel = new QLabel(this);
modifiedCardsArea = new QScrollArea(this);
modifiedCardsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
modifiedCardsArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
modifiedCardsArea->setWidgetResizable(true);
modifiedCardsFlowWidget =
new FlowWidget(modifiedCardsArea, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
modifiedCardsArea->setWidget(modifiedCardsFlowWidget);
rightLayout->addWidget(modifiedCardsLabel);
rightLayout->addWidget(modifiedCardsArea);
rightContainer->setLayout(rightLayout);
// Add left and right containers to the bottom splitter
bottomSplitter->addWidget(leftContainer);
bottomSplitter->addWidget(rightContainer);
// Add widgets to the main splitter
splitter->addWidget(scrollArea);
splitter->addWidget(bottomSplitter);
cardsForSets = getCardsForSets();
sortSetsByCount();
updateCardLists();
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOK()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
clearButton = new QPushButton(buttonBox);
connect(clearButton, &QPushButton::clicked, this, &DlgSelectSetForCards::actClear);
setAllToPreferredButton = new QPushButton(buttonBox);
connect(setAllToPreferredButton, &QPushButton::clicked, this, &DlgSelectSetForCards::actSetAllToPreferred);
buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(setAllToPreferredButton, QDialogButtonBox::ActionRole);
// Set stretch factors
splitter->setStretchFactor(0, 6); // Scroll area gets more space
splitter->setStretchFactor(1, 2); // Bottom part gets less space
splitter->setStretchFactor(2, 1); // Buttons take minimal space
bottomSplitter->setStretchFactor(0, 1); // Left and right equally split
bottomSplitter->setStretchFactor(1, 1);
connect(this, &DlgSelectSetForCards::orderChanged, this, &DlgSelectSetForCards::updateLayoutOrder);
connect(this, &DlgSelectSetForCards::widgetOrderChanged, this, &DlgSelectSetForCards::updateCardLists);
mainLayout->addWidget(instructionLabel);
mainLayout->addWidget(splitter);
mainLayout->addWidget(buttonBox);
retranslateUi();
setWindowFlags(Qt::Window);
showMaximized();
}
void DlgSelectSetForCards::retranslateUi()
{
uneditedCardsLabel->setText(tr("Unmodified Cards:"));
modifiedCardsLabel->setText(tr("Modified Cards:"));
instructionLabel->setText(tr("Check Sets to enable them. Drag-and-Drop to reorder them and change their "
"priority. Cards will use the printing of the highest priority enabled set."));
clearButton->setText(tr("Clear all set information"));
setAllToPreferredButton->setText(tr("Set all to preferred"));
}
void DlgSelectSetForCards::actOK()
{
QMap<QString, QStringList> modifiedSetsAndCardsMap = getModifiedCards();
for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) {
for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) {
QModelIndex find_card = model->findCard(card, DECK_ZONE_MAIN);
if (!find_card.isValid()) {
continue;
}
model->removeRow(find_card.row(), find_card.parent());
CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(card);
PrintingInfo printing = CardDatabaseManager::query()->getSpecificPrinting(card, modifiedSet, "");
model->addCard(ExactCard(cardInfo, printing), DECK_ZONE_MAIN);
}
}
accept();
}
void DlgSelectSetForCards::actClear()
{
model->getDeckList()->clearSetNamesAndNumbers();
accept();
}
void DlgSelectSetForCards::actSetAllToPreferred()
{
model->getDeckList()->clearSetNamesAndNumbers();
model->getDeckList()->setProviderIdToPreferredPrinting();
accept();
}
void DlgSelectSetForCards::sortSetsByCount()
{
QMap<QString, int> setsForCards = getSetsForCards();
// Convert map to a sortable list
QVector<QPair<QString, int>> setList;
for (auto it = setsForCards.begin(); it != setsForCards.end(); ++it) {
setList.append(qMakePair(it.key(), it.value()));
}
// Sort in descending order of count
std::sort(setList.begin(), setList.end(),
[](const QPair<QString, int> &a, const QPair<QString, int> &b) { return a.second > b.second; });
// Clear existing entries
qDeleteAll(setEntries);
setEntries.clear();
// Populate with sorted entries
for (const auto &entry : setList) {
SetEntryWidget *widget = new SetEntryWidget(this, entry.first, entry.second);
listLayout->addWidget(widget);
setEntries.insert(entry.first, widget);
}
}
QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
{
QMap<QString, int> setCounts;
if (!model)
return setCounts;
DeckList *decklist = model->getDeckList();
if (!decklist)
return setCounts;
InnerDecklistNode *listRoot = decklist->getRoot();
if (!listRoot)
return setCounts;
for (auto *i : *listRoot) {
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
if (!countCurrentZone)
continue;
for (auto *cardNode : *countCurrentZone) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
if (!currentCard)
continue;
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (!infoPtr)
continue;
SetToPrintingsMap setMap = infoPtr->getSets();
for (auto &setName : setMap.keys()) {
setCounts[setName]++;
}
}
}
return setCounts;
}
void DlgSelectSetForCards::updateCardLists()
{
for (SetEntryWidget *entryWidget : entry_widgets) {
entryWidget->populateCardList();
if (entryWidget->expanded) {
entryWidget->updateCardDisplayWidgets();
}
entryWidget->checkVisibility();
}
uneditedCardsFlowWidget->clearLayout();
modifiedCardsFlowWidget->clearLayout();
// Map from set name to a set of selected cards in that set
QMap<QString, QSet<QString>> selectedCardsBySet;
for (SetEntryWidget *entryWidget : entry_widgets) {
if (entryWidget->isChecked()) {
QStringList cardsInSet = entryWidget->getAllCardsForSet();
QSet<QString> cardSet = QSet<QString>(cardsInSet.begin(), cardsInSet.end()); // Convert list to set
selectedCardsBySet.insert(entryWidget->setName, cardSet);
}
}
DeckList *decklist = model->getDeckList();
if (!decklist)
return;
InnerDecklistNode *listRoot = decklist->getRoot();
if (!listRoot)
return;
for (auto *i : *listRoot) {
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
if (!countCurrentZone)
continue;
for (auto *cardNode : *countCurrentZone) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
if (!currentCard)
continue;
bool found = false;
QString foundSetName;
// Check across all sets if the card is present
for (auto it = selectedCardsBySet.begin(); it != selectedCardsBySet.end(); ++it) {
if (it.value().contains(currentCard->getName())) {
found = true;
foundSetName = it.key(); // Store the set name where it was found
break; // Stop at the first match
}
}
if (!found) {
// The card was not in any selected set
ExactCard card = CardDatabaseManager::query()->getCard({currentCard->getName()});
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget);
picture_widget->setCard(card);
uneditedCardsFlowWidget->addWidget(picture_widget);
} else {
ExactCard card = CardDatabaseManager::query()->getCard(
{currentCard->getName(), CardDatabaseManager::getInstance()
->query()
->getSpecificPrinting(currentCard->getName(), foundSetName, "")
.getUuid()});
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget);
picture_widget->setCard(card);
modifiedCardsFlowWidget->addWidget(picture_widget);
}
}
}
}
void DlgSelectSetForCards::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("application/x-setentrywidget")) {
// Highlight the drop target area
event->acceptProposedAction();
// Optionally, change cursor to indicate a valid drop area
setCursor(Qt::OpenHandCursor);
}
}
void DlgSelectSetForCards::dropEvent(QDropEvent *event)
{
QByteArray itemData = event->mimeData()->data("application/x-setentrywidget");
QString draggedSetName = QString::fromUtf8(itemData);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
QPoint adjustedPos = event->position().toPoint() + QPoint(0, scrollArea->verticalScrollBar()->value());
#else
QPoint adjustedPos = event->pos() + QPoint(0, scrollArea->verticalScrollBar()->value());
#endif
int dropIndex = -1;
for (int i = 0; i < listLayout->count(); ++i) {
QWidget *widget = listLayout->itemAt(i)->widget();
if (widget && widget->geometry().contains(adjustedPos)) {
dropIndex = i;
break;
}
}
if (dropIndex != -1) {
// Find the dragged widget and move it to the new position
SetEntryWidget *draggedWidget = setEntries.value(draggedSetName, nullptr);
if (draggedWidget) {
listLayout->removeWidget(draggedWidget);
listLayout->insertWidget(dropIndex, draggedWidget);
}
}
event->acceptProposedAction();
// Reset cursor after drop
unsetCursor();
// We need to execute this AFTER the current event-cycle so we use a timer.
QTimer::singleShot(10, this, [this]() { emit orderChanged(); });
}
QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
{
QMap<QString, QStringList> setCards;
if (!model)
return setCards;
DeckList *decklist = model->getDeckList();
if (!decklist)
return setCards;
InnerDecklistNode *listRoot = decklist->getRoot();
if (!listRoot)
return setCards;
for (auto *i : *listRoot) {
auto *countCurrentZone = dynamic_cast<InnerDecklistNode *>(i);
if (!countCurrentZone)
continue;
for (auto *cardNode : *countCurrentZone) {
auto *currentCard = dynamic_cast<DecklistCardNode *>(cardNode);
if (!currentCard)
continue;
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
if (!infoPtr)
continue;
SetToPrintingsMap setMap = infoPtr->getSets();
for (auto it = setMap.begin(); it != setMap.end(); ++it) {
setCards[it.key()].append(currentCard->getName());
}
}
}
return setCards;
}
QMap<QString, QStringList> DlgSelectSetForCards::getModifiedCards()
{
QMap<QString, QStringList> modifiedCards;
for (int i = 0; i < listLayout->count(); ++i) {
QWidget *widget = listLayout->itemAt(i)->widget();
if (auto entry = qobject_cast<SetEntryWidget *>(widget)) {
if (entry->isChecked()) {
QStringList cardsInSet = entry->getAllCardsForSet();
for (QString cardInSet : cardsInSet) {
bool alreadyContained = false;
for (QString key : modifiedCards.keys()) {
if (modifiedCards[key].contains(cardInSet)) {
alreadyContained = true;
}
}
if (!alreadyContained) {
modifiedCards[entry->setName].append(cardInSet);
}
}
}
}
}
return modifiedCards;
}
void DlgSelectSetForCards::updateLayoutOrder()
{
entry_widgets.clear();
for (int i = 0; i < listLayout->count(); ++i) {
QWidget *widget = listLayout->itemAt(i)->widget();
if (auto entry = qobject_cast<SetEntryWidget *>(widget)) {
entry_widgets.append(entry);
}
}
emit widgetOrderChanged();
}
SetEntryWidget::SetEntryWidget(DlgSelectSetForCards *_parent, const QString &_setName, int count)
: QWidget(_parent), parent(_parent), setName(_setName), expanded(false)
{
layout = new QVBoxLayout(this);
setLayout(layout);
QHBoxLayout *headerLayout = new QHBoxLayout();
CardSetPtr set = CardDatabaseManager::getInstance()->getSet(setName);
checkBox = new QCheckBox("(" + set->getShortName() + ") - " + set->getLongName(), this);
connect(checkBox, &QCheckBox::toggled, parent, &DlgSelectSetForCards::updateLayoutOrder);
expandButton = new QPushButton("+", this);
countLabel = new QLabel(QString::number(count), this);
connect(expandButton, &QPushButton::clicked, this, &SetEntryWidget::toggleExpansion);
headerLayout->addWidget(checkBox);
headerLayout->addWidget(countLabel);
headerLayout->addWidget(expandButton);
layout->addLayout(headerLayout);
possibleCardsLabel = new QLabel(this);
possibleCardsLabel->setText("Unselected cards in set:");
possibleCardsLabel->hide();
cardListContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
cardListContainer->hide();
alreadySelectedCardsLabel = new QLabel(this);
alreadySelectedCardsLabel->setText("Cards in set already selected in higher priority set:");
alreadySelectedCardsLabel->hide();
alreadySelectedCardListContainer =
new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff);
alreadySelectedCardListContainer->hide();
layout->addWidget(possibleCardsLabel);
layout->addWidget(cardListContainer);
layout->addWidget(alreadySelectedCardsLabel);
layout->addWidget(alreadySelectedCardListContainer);
setAttribute(Qt::WA_DeleteOnClose, false);
setAttribute(Qt::WA_StyledBackground, true);
}
void SetEntryWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
// Create a drag object and set up mime data
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
// Set the mime data to store the dragged set's name
mimeData->setData("application/x-setentrywidget", setName.toUtf8());
drag->setMimeData(mimeData);
// Create a "ghost" pixmap to represent the widget during dragging
QPixmap pixmap = this->grab();
// Ensure pixmap has a transparent background
QImage image = pixmap.toImage();
for (int y = 0; y < image.height(); ++y) {
for (int x = 0; x < image.width(); ++x) {
if (image.pixel(x, y) == Qt::transparent) {
image.setPixel(x, y, QColor(0, 0, 0, 0).rgba()); // Set transparency where needed
}
}
}
pixmap = QPixmap::fromImage(image); // Convert back to pixmap after transparency manipulation
// Set the pixmap for the drag object
drag->setPixmap(pixmap);
// Optionally adjust the pixmap position offset to align with the cursor
drag->setHotSpot(event->pos());
drag->exec(Qt::MoveAction);
}
}
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void SetEntryWidget::enterEvent(QEnterEvent *event)
#else
void SetEntryWidget::enterEvent(QEvent *event)
#endif
{
QWidget::enterEvent(event); // Call the base class handler
// Highlight the widget by changing the background color only for the widget itself
setStyleSheet("SetEntryWidget { background: gray; }");
// Change cursor to open hand
setCursor(Qt::OpenHandCursor);
repaint();
}
void SetEntryWidget::leaveEvent(QEvent *event)
{
QWidget::leaveEvent(event); // Call the base class handler
// Reset the background color only for the widget itself
setStyleSheet("SetEntryWidget { background: none; }");
// Reset cursor to default
setCursor(Qt::ArrowCursor);
repaint();
}
void SetEntryWidget::dragMoveEvent(QDragMoveEvent *event)
{
// Check if the mime data is of the correct type
if (event->mimeData()->hasFormat("application/x-setentrywidget")) {
setCursor(Qt::ClosedHandCursor); // Hand cursor to indicate move
// Get the current position of the widget being dragged
// For now, we will just highlight the widget when dragged.
QPainter painter(this);
QColor highlightColor(255, 255, 255, 128); // Semi-transparent white
painter.setBrush(QBrush(highlightColor));
painter.setPen(Qt::NoPen);
painter.drawRect(this->rect()); // Highlight the widget area
// Allow the widget to be moved to the new position
event->acceptProposedAction();
} else {
event->ignore();
}
}
bool SetEntryWidget::isChecked() const
{
return checkBox->isChecked();
}
void SetEntryWidget::toggleExpansion()
{
expanded = !expanded;
possibleCardsLabel->setVisible(expanded);
cardListContainer->setVisible(expanded);
alreadySelectedCardsLabel->setVisible(expanded);
alreadySelectedCardListContainer->setVisible(expanded);
expandButton->setText(expanded ? "-" : "+");
populateCardList();
updateCardDisplayWidgets();
parent->updateCardLists();
}
void SetEntryWidget::checkVisibility()
{
if (possibleCards.empty()) {
setHidden(true);
} else {
setVisible(true);
}
}
QStringList SetEntryWidget::getAllCardsForSet()
{
QStringList list;
QMap<QString, QStringList> setCards = parent->cardsForSets;
if (setCards.contains(setName)) {
for (const QString &cardName : setCards[setName]) {
list << cardName;
}
}
return list;
}
void SetEntryWidget::populateCardList()
{
possibleCards = getAllCardsForSet();
for (SetEntryWidget *entryWidget : parent->entry_widgets) {
if (entryWidget == this) {
break;
}
if (entryWidget->isChecked()) {
for (const QString &cardName : entryWidget->possibleCards) {
possibleCards.removeAll(cardName);
}
}
}
unusedCards = getAllCardsForSet();
for (const QString &cardName : possibleCards) {
unusedCards.removeAll(cardName);
}
checkVisibility();
countLabel->setText(QString::number(possibleCards.size()) + " (" +
QString::number(possibleCards.size() + unusedCards.size()) + ")");
}
void SetEntryWidget::updateCardDisplayWidgets()
{
cardListContainer->clearLayout();
alreadySelectedCardListContainer->clearLayout();
for (const QString &cardName : possibleCards) {
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(cardListContainer);
QString providerId = CardDatabaseManager::query()->getSpecificPrinting(cardName, setName, nullptr).getUuid();
picture_widget->setCard(CardDatabaseManager::query()->getCard({cardName, providerId}));
cardListContainer->addWidget(picture_widget);
}
for (const QString &cardName : unusedCards) {
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(alreadySelectedCardListContainer);
QString providerId = CardDatabaseManager::query()->getSpecificPrinting(cardName, setName, nullptr).getUuid();
picture_widget->setCard(CardDatabaseManager::query()->getCard({cardName, providerId}));
alreadySelectedCardListContainer->addWidget(picture_widget);
}
}

View file

@ -0,0 +1,110 @@
/**
* @file dlg_select_set_for_cards.h
* @ingroup Dialogs
* @brief TODO: Document this.
*/
#ifndef DLG_SELECT_SET_FOR_CARDS_H
#define DLG_SELECT_SET_FOR_CARDS_H
#include "../interface/widgets/general/layout_containers/flow_widget.h"
#include <QCheckBox>
#include <QDialog>
#include <QLabel>
#include <QListWidget>
#include <QMap>
#include <QScrollArea>
#include <QVBoxLayout>
#include <libcockatrice/deck_list/deck_list_model.h>
class SetEntryWidget; // Forward declaration
class DlgSelectSetForCards : public QDialog
{
Q_OBJECT
public:
explicit DlgSelectSetForCards(QWidget *parent, DeckListModel *_model);
void retranslateUi();
void sortSetsByCount();
QMap<QString, QStringList> getCardsForSets();
QMap<QString, QStringList> getModifiedCards();
QVBoxLayout *listLayout;
QList<SetEntryWidget *> entry_widgets;
QMap<QString, QStringList> cardsForSets;
signals:
void widgetOrderChanged();
void orderChanged();
public slots:
void actOK();
void actClear();
void actSetAllToPreferred();
void updateLayoutOrder();
void updateCardLists();
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
private:
QVBoxLayout *layout;
QLabel *instructionLabel;
QScrollArea *scrollArea;
QScrollArea *uneditedCardsArea;
FlowWidget *uneditedCardsFlowWidget;
QLabel *uneditedCardsLabel;
QScrollArea *modifiedCardsArea;
FlowWidget *modifiedCardsFlowWidget;
QLabel *modifiedCardsLabel;
QWidget *listContainer;
QListWidget *listWidget;
DeckListModel *model;
QMap<QString, SetEntryWidget *> setEntries;
QPushButton *clearButton;
QPushButton *setAllToPreferredButton;
QMap<QString, int> getSetsForCards();
};
class SetEntryWidget : public QWidget
{
Q_OBJECT
public:
explicit SetEntryWidget(DlgSelectSetForCards *parent, const QString &setName, int count);
void toggleExpansion();
void checkVisibility();
QStringList getAllCardsForSet();
void populateCardList();
void updateCardDisplayWidgets();
bool isChecked() const;
DlgSelectSetForCards *parent;
QString setName;
bool expanded;
public slots:
void mousePressEvent(QMouseEvent *event) override;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
void enterEvent(QEnterEvent *event) override;
#else
void enterEvent(QEvent *event) override;
#endif
void leaveEvent(QEvent *event) override;
void dragMoveEvent(QDragMoveEvent *event) override;
private:
QVBoxLayout *layout;
QCheckBox *checkBox;
QPushButton *expandButton;
QLabel *countLabel;
QLabel *possibleCardsLabel;
FlowWidget *cardListContainer;
QLabel *alreadySelectedCardsLabel;
FlowWidget *alreadySelectedCardListContainer;
QVBoxLayout *cardListLayout;
QStringList possibleCards;
QStringList unusedCards;
};
#endif // DLG_SELECT_SET_FOR_CARDS_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,358 @@
/**
* @file dlg_settings.h
* @ingroup Dialogs
* @brief TODO: Document this.
*/
#ifndef DLG_SETTINGS_H
#define DLG_SETTINGS_H
#include <QCheckBox>
#include <QComboBox>
#include <QDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLoggingCategory>
#include <QPushButton>
#include <QSpinBox>
#include <libcockatrice/utility/macros.h>
inline Q_LOGGING_CATEGORY(DlgSettingsLog, "dlg_settings");
class ShortcutTreeView;
class SearchLineEdit;
class QTreeView;
class QStandardItemModel;
class CardDatabase;
class QCloseEvent;
class QGridLayout;
class QHBoxLayout;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
class QRadioButton;
class QSlider;
class QStackedWidget;
class QVBoxLayout;
class SequenceEdit;
class AbstractSettingsPage : public QWidget
{
public:
virtual void retranslateUi() = 0;
};
class GeneralSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
public:
GeneralSettingsPage();
void retranslateUi() override;
private slots:
void deckPathButtonClicked();
void filtersPathButtonClicked();
void replaysPathButtonClicked();
void picsPathButtonClicked();
void cardDatabasePathButtonClicked();
void customCardDatabaseButtonClicked();
void tokenDatabasePathButtonClicked();
void resetAllPathsClicked();
void languageBoxChanged(int index);
private:
QStringList findQmFiles();
QString languageName(const QString &lang);
QLineEdit *deckPathEdit;
QLineEdit *filtersPathEdit;
QLineEdit *replaysPathEdit;
QLineEdit *picsPathEdit;
QLineEdit *cardDatabasePathEdit;
QLineEdit *customCardDatabasePathEdit;
QLineEdit *tokenDatabasePathEdit;
QPushButton *resetAllPathsButton;
QLabel *allPathsResetLabel;
QGroupBox *personalGroupBox;
QGroupBox *pathsGroupBox;
QComboBox languageBox;
QCheckBox startupUpdateCheckCheckBox;
QLabel startupCardUpdateCheckBehaviorLabel;
QComboBox startupCardUpdateCheckBehaviorSelector;
QLabel cardUpdateCheckIntervalLabel;
QSpinBox cardUpdateCheckIntervalSpinBox;
QLabel lastCardUpdateCheckDateLabel;
QCheckBox updateNotificationCheckBox;
QCheckBox newVersionOracleCheckBox;
QComboBox updateReleaseChannelBox;
QLabel languageLabel;
QLabel deckPathLabel;
QLabel filtersPathLabel;
QLabel replaysPathLabel;
QLabel picsPathLabel;
QLabel cardDatabasePathLabel;
QLabel customCardDatabasePathLabel;
QLabel tokenDatabasePathLabel;
QLabel updateReleaseChannelLabel;
QLabel advertiseTranslationPageLabel;
QCheckBox showTipsOnStartup;
};
class AppearanceSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
private slots:
void themeBoxChanged(int index);
void openThemeLocation();
void showShortcutsChanged(QT_STATE_CHANGED_T enabled);
void overrideAllCardArtWithPersonalPreferenceToggled(QT_STATE_CHANGED_T enabled);
void cardViewInitialRowsMaxChanged(int value);
void cardViewExpandedRowsMaxChanged(int value);
private:
QLabel themeLabel;
QComboBox themeBox;
QPushButton openThemeButton;
QLabel homeTabBackgroundSourceLabel;
QComboBox homeTabBackgroundSourceBox;
QLabel homeTabBackgroundShuffleFrequencyLabel;
QSpinBox homeTabBackgroundShuffleFrequencySpinBox;
QLabel minPlayersForMultiColumnLayoutLabel;
QLabel maxFontSizeForCardsLabel;
QCheckBox showShortcutsCheckBox;
QCheckBox displayCardNamesCheckBox;
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
QCheckBox overrideAllCardArtWithPersonalPreferenceCheckBox;
QCheckBox bumpSetsWithCardsInDeckToTopCheckBox;
QCheckBox cardScalingCheckBox;
QCheckBox roundCardCornersCheckBox;
QLabel verticalCardOverlapPercentLabel;
QSpinBox verticalCardOverlapPercentBox;
QLabel cardViewInitialRowsMaxLabel;
QSpinBox cardViewInitialRowsMaxBox;
QLabel cardViewExpandedRowsMaxLabel;
QSpinBox cardViewExpandedRowsMaxBox;
QCheckBox horizontalHandCheckBox;
QCheckBox leftJustifiedHandCheckBox;
QCheckBox invertVerticalCoordinateCheckBox;
QGroupBox *themeGroupBox;
QGroupBox *menuGroupBox;
QGroupBox *cardsGroupBox;
QGroupBox *handGroupBox;
QGroupBox *tableGroupBox;
QGroupBox *cardCountersGroupBox;
QList<QLabel *> cardCounterNames;
QSpinBox minPlayersForMultiColumnLayoutEdit;
QSpinBox maxFontSizeForCardsEdit;
public:
AppearanceSettingsPage();
void retranslateUi() override;
};
class UserInterfaceSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
private slots:
void setNotificationEnabled(QT_STATE_CHANGED_T);
private:
QCheckBox notificationsEnabledCheckBox;
QCheckBox specNotificationsEnabledCheckBox;
QCheckBox buddyConnectNotificationsEnabledCheckBox;
QCheckBox doubleClickToPlayCheckBox;
QCheckBox clickPlaysAllSelectedCheckBox;
QCheckBox playToStackCheckBox;
QCheckBox closeEmptyCardViewCheckBox;
QCheckBox focusCardViewSearchBarCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox tapAnimationCheckBox;
QCheckBox openDeckInNewTabCheckBox;
QLabel visualDeckStoragePromptForConversionLabel;
QComboBox visualDeckStoragePromptForConversionSelector;
QCheckBox visualDeckStorageInGameCheckBox;
QCheckBox visualDeckStorageSelectionAnimationCheckBox;
QLabel defaultDeckEditorTypeLabel;
QComboBox defaultDeckEditorTypeSelector;
QLabel rewindBufferingMsLabel;
QSpinBox rewindBufferingMsBox;
QGroupBox *generalGroupBox;
QGroupBox *notificationsGroupBox;
QGroupBox *animationGroupBox;
QGroupBox *deckEditorGroupBox;
QGroupBox *replayGroupBox;
public:
UserInterfaceSettingsPage();
void retranslateUi() override;
};
class DeckEditorSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
public:
DeckEditorSettingsPage();
void retranslateUi() override;
QString getLastUpdateTime();
private slots:
void storeSettings();
void urlListChanged(const QModelIndex &, int, int, const QModelIndex &, int);
void setSpoilersEnabled(bool);
void spoilerPathButtonClicked();
void updateSpoilers();
void unlockSettings();
void actAddURL();
void actRemoveURL();
void actEditURL();
void clearDownloadedPicsButtonClicked();
void resetDownloadedURLsButtonClicked();
private:
QPushButton clearDownloadedPicsButton;
QPushButton resetDownloadURLs;
QLabel urlLinkLabel;
QCheckBox picDownloadCheckBox;
QListWidget *urlList;
QAction *aAdd, *aEdit, *aRemove;
QCheckBox mcDownloadSpoilersCheckBox;
QLabel msDownloadSpoilersLabel;
QGroupBox *mpGeneralGroupBox;
QGroupBox *mpSpoilerGroupBox;
QLineEdit *mpSpoilerSavePathLineEdit;
QLabel mcSpoilerSaveLabel;
QLabel lastUpdatedLabel;
QLabel infoOnSpoilersLabel;
QPushButton *mpSpoilerPathButton;
QPushButton *updateNowButton;
QLabel networkCacheLabel;
QSpinBox networkCacheEdit;
QLabel networkRedirectCacheTtlLabel;
QSpinBox networkRedirectCacheTtlEdit;
QSpinBox pixmapCacheEdit;
QLabel pixmapCacheLabel;
};
class MessagesSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
public:
MessagesSettingsPage();
void retranslateUi() override;
private slots:
void actAdd();
void actEdit();
void actRemove();
void updateColor(const QString &value);
void updateHighlightColor(const QString &value);
void updateTextColor(QT_STATE_CHANGED_T value);
void updateTextHighlightColor(QT_STATE_CHANGED_T value);
private:
QListWidget *messageList;
QAction *aAdd;
QAction *aEdit;
QAction *aRemove;
QCheckBox chatMentionCheckBox;
QCheckBox chatMentionCompleterCheckbox;
QCheckBox invertMentionForeground;
QCheckBox invertHighlightForeground;
QCheckBox ignoreUnregUsersMainChat;
QCheckBox ignoreUnregUserMessages;
QCheckBox messagePopups;
QCheckBox mentionPopups;
QCheckBox roomHistory;
QGroupBox *chatGroupBox;
QGroupBox *highlightGroupBox;
QGroupBox *messageGroupBox;
QLineEdit *mentionColor;
QLineEdit *highlightColor;
QLineEdit *customAlertString;
QLabel hexLabel;
QLabel hexHighlightLabel;
QLabel customAlertStringLabel;
QLabel explainMessagesLabel;
void storeSettings();
void updateMentionPreview();
void updateHighlightPreview();
};
class SoundSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
public:
SoundSettingsPage();
void retranslateUi() override;
private:
QLabel themeLabel;
QComboBox themeBox;
QGroupBox *soundGroupBox;
QPushButton soundTestButton;
QCheckBox soundEnabledCheckBox;
QLabel masterVolumeLabel;
QSlider *masterVolumeSlider;
QSpinBox *masterVolumeSpinBox;
private slots:
void masterVolumeChanged(int value);
void themeBoxChanged(int index);
};
class ShortcutSettingsPage : public AbstractSettingsPage
{
Q_OBJECT
public:
ShortcutSettingsPage();
void retranslateUi() override;
private:
SearchLineEdit *searchEdit;
ShortcutTreeView *shortcutsTable;
QVBoxLayout *mainLayout;
QHBoxLayout *buttonsLayout;
QGroupBox *editShortcutGroupBox;
QGridLayout *editLayout;
QLabel *currentActionGroupLabel;
QLabel *currentActionGroupName;
QLabel *currentActionLabel;
QLabel *currentActionName;
QLabel *currentShortcutLabel;
SequenceEdit *editTextBox;
QLabel *faqLabel;
QPushButton *btnResetAll;
QPushButton *btnClearAll;
private slots:
void resetShortcuts();
void clearShortcuts();
void currentItemChanged(const QString &key);
};
class DlgSettings : public QDialog
{
Q_OBJECT
public:
explicit DlgSettings(QWidget *parent = nullptr);
void setTab(int index);
private slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
void updateLanguage();
private:
QListWidget *contentsWidget;
QStackedWidget *pagesWidget;
QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *messagesButton,
*soundButton, *shortcutsButton;
void createIcons();
void retranslateUi();
protected:
void closeEvent(QCloseEvent *event) override;
};
#endif

View file

@ -0,0 +1,49 @@
#include "dlg_startup_card_check.h"
#include <QDate>
#include <libcockatrice/settings/cache_settings.h>
DlgStartupCardCheck::DlgStartupCardCheck(QWidget *parent) : QDialog(parent)
{
setWindowTitle(tr("Card Update Check"));
layout = new QVBoxLayout(this);
QDate lastCheckDate = SettingsCache::instance().getLastCardUpdateCheck();
int daysAgo = lastCheckDate.daysTo(QDate::currentDate());
instructionLabel = new QLabel(
tr("It has been more than %2 days since you last checked your card database for updates.\nChoose how you would "
"like to run the card database updater.\nYou can always change this behavior in the 'General' settings tab.")
.arg(daysAgo));
layout->addWidget(instructionLabel);
group = new QButtonGroup(this);
foregroundBtn = new QRadioButton(tr("Run in foreground"));
backgroundBtn = new QRadioButton(tr("Run in background"));
backgroundAlwaysBtn = new QRadioButton(tr("Run in background and always from now on"));
dontPromptBtn = new QRadioButton(tr("Don't prompt again and don't run"));
dontRunBtn = new QRadioButton(tr("Don't run this time"));
group->addButton(foregroundBtn, 0);
group->addButton(backgroundBtn, 1);
group->addButton(backgroundAlwaysBtn, 2);
group->addButton(dontPromptBtn, 3);
group->addButton(dontRunBtn, 4);
foregroundBtn->setChecked(true); // default
layout->addWidget(foregroundBtn);
layout->addWidget(backgroundBtn);
layout->addWidget(backgroundAlwaysBtn);
layout->addWidget(dontPromptBtn);
layout->addWidget(dontRunBtn);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}

View file

@ -0,0 +1,30 @@
/**
* @file dlg_startup_card_check.h
* @ingroup CardDatabaseUpdateDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_STARTUP_CARD_CHECK_H
#define DLG_STARTUP_CARD_CHECK_H
#include <QButtonGroup>
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QRadioButton>
#include <QVBoxLayout>
class DlgStartupCardCheck : public QDialog
{
Q_OBJECT
public:
explicit DlgStartupCardCheck(QWidget *parent);
QVBoxLayout *layout;
QLabel *instructionLabel;
QButtonGroup *group;
QRadioButton *foregroundBtn, *backgroundBtn, *backgroundAlwaysBtn, *dontPromptBtn, *dontRunBtn;
QDialogButtonBox *buttonBox;
};
#endif // DLG_STARTUP_CARD_CHECK_H

View file

@ -0,0 +1,172 @@
#include "dlg_tip_of_the_day.h"
#include "tip_of_the_day.h"
#include <QCheckBox>
#include <QDate>
#include <QDebug>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <libcockatrice/settings/cache_settings.h>
#define MIN_TIP_IMAGE_HEIGHT 200
#define MIN_TIP_IMAGE_WIDTH 200
#define MAX_TIP_IMAGE_HEIGHT 300
#define MAX_TIP_IMAGE_WIDTH 500
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);
QList<int> seenTips = SettingsCache::instance().getSeenTips();
newTipsAvailable = false;
currentTip = 0;
for (int i = 0; i < tipDatabase->rowCount(); i++) {
if (!seenTips.contains(i)) {
newTipsAvailable = true;
currentTip = i;
break;
}
}
connect(this, &DlgTipOfTheDay::newTipRequested, this, &DlgTipOfTheDay::updateTip);
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, &QDialogButtonBox::accepted, this, &DlgTipOfTheDay::accept);
connect(nextButton, &QPushButton::clicked, this, &DlgTipOfTheDay::nextClicked);
connect(previousButton, &QPushButton::clicked, this, &DlgTipOfTheDay::previousClicked);
showTipsOnStartupCheck = new QCheckBox("Show tips on startup");
showTipsOnStartupCheck->setChecked(SettingsCache::instance().getShowTipsOnStartup());
connect(showTipsOnStartupCheck, &QCheckBox::clicked, &SettingsCache::instance(),
&SettingsCache::setShowTipsOnStartup);
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(700);
setMinimumHeight(500);
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();
}
// Store tip id as seen
QList<int> seenTips = SettingsCache::instance().getSeenTips();
if (!seenTips.contains(tipId)) {
seenTips.append(tipId);
SettingsCache::instance().setSeenTips(seenTips);
}
TipOfTheDay tip = tipDatabase->getTip(tipId);
titleText = tip.getTitle();
contentText = tip.getContent();
imagePath = tip.getImagePath();
title->setText("<h2>" + titleText + "</h2>");
tipTextContent->setText(contentText);
tipTextContent->setTextFormat(Qt::RichText);
if (!image->load(imagePath)) {
qCWarning(DlgTipOfTheDayLog) << "Image failed to load from" << imagePath;
imageLabel->clear();
} else {
int h = std::min(std::max(imageLabel->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(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
date->setText("<i>Tip added on: " + tip.getDate().toString("yyyy-MM-dd") + "</i>");
tipNumber->setText("Tip " + QString::number(tipId + 1) + " / " + QString::number(tipDatabase->rowCount()));
currentTip = static_cast<unsigned int>(tipId);
adjustSize();
}
void DlgTipOfTheDay::resizeEvent(QResizeEvent *event)
{
imageLabel->setPixmap(image->scaled(imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
QWidget::resizeEvent(event);
}

View file

@ -0,0 +1,58 @@
/**
* @file dlg_tip_of_the_day.h
* @ingroup Dialogs
* @brief TODO: Document this.
*/
#ifndef DLG_TIPOFDAY_H
#define DLG_TIPOFDAY_H
#include <QComboBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QLoggingCategory>
#include <QPushButton>
#include <QVBoxLayout>
inline Q_LOGGING_CATEGORY(DlgTipOfTheDayLog, "dlg_tip_of_the_day");
class QLabel;
class QPushButton;
class QCheckBox;
class TipsOfTheDay;
class DlgTipOfTheDay : public QDialog
{
Q_OBJECT
public:
explicit DlgTipOfTheDay(QWidget *parent = nullptr);
~DlgTipOfTheDay() override;
bool successfulInit;
bool newTipsAvailable;
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

View file

@ -0,0 +1,241 @@
#include "dlg_update.h"
#include "../client/network/update/client/client_update_checker.h"
#include "../client/network/update/client/release_channel.h"
#include "../interface/window_main.h"
#include <QApplication>
#include <QDesktopServices>
#include <QLabel>
#include <QMessageBox>
#include <QProgressBar>
#include <QProgressDialog>
#include <QPushButton>
#include <QVBoxLayout>
#include <QtNetwork>
#include <libcockatrice/settings/cache_settings.h>
#include <version_string.h>
DlgUpdate::DlgUpdate(QWidget *parent) : QDialog(parent)
{
// Handle layout
statusLabel = new QLabel(this);
statusLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
statusLabel->setWordWrap(true);
descriptionLabel =
new QLabel(tr("Current release channel") +
QString(": %1").arg(tr(SettingsCache::instance().getUpdateReleaseChannel()->getName().toUtf8())),
this);
progress = new QProgressBar(this);
buttonBox = new QDialogButtonBox(this);
buttonBox->setFixedWidth(350);
ok = new QPushButton("Close", this);
manualDownload = new QPushButton(tr("Reinstall"), this);
stopDownload = new QPushButton(tr("Cancel Download"), this);
gotoDownload = new QPushButton(tr("Open Download Page"), this);
addStopDownloadAndRemoveOthers(false); // Add all buttons to box
enableUpdateButton(false); // Unless we know there's an update available, you can't install
buttonBox->addButton(ok, QDialogButtonBox::AcceptRole);
connect(gotoDownload, &QPushButton::clicked, this, &DlgUpdate::gotoDownloadPage);
// TODO: make reinstall button actually do something when clicked
// connect(manualDownload, &QPushButton::clicked, this, &DlgUpdate::downloadUpdate);
connect(stopDownload, &QPushButton::clicked, this, &DlgUpdate::cancelDownload);
connect(ok, &QPushButton::clicked, this, &DlgUpdate::closeDialog);
auto *parentLayout = new QVBoxLayout(this);
parentLayout->addWidget(descriptionLabel);
parentLayout->addWidget(statusLabel);
parentLayout->addWidget(progress);
parentLayout->addWidget(buttonBox);
setLayout(parentLayout);
setWindowTitle(tr("Check for Client Updates"));
setFixedHeight(this->sizeHint().height());
setFixedWidth(this->sizeHint().width());
// Check for SSL (this probably isn't necessary)
if (!QSslSocket::supportsSsl()) {
enableUpdateButton(false);
QMessageBox::critical(this, tr("Error"),
tr("Cockatrice was not built with SSL support, therefore you cannot download updates "
"automatically! \nPlease visit the download page to update manually."));
}
// Initialize the checker and downloader class
uDownloader = new UpdateDownloader(this);
connect(uDownloader, &UpdateDownloader::downloadSuccessful, this, &DlgUpdate::downloadSuccessful);
connect(uDownloader, &UpdateDownloader::progressMade, this, &DlgUpdate::downloadProgressMade);
connect(uDownloader, &UpdateDownloader::error, this, &DlgUpdate::downloadError);
// Check for updates
beginUpdateCheck();
}
void DlgUpdate::closeDialog()
{
accept();
}
void DlgUpdate::gotoDownloadPage()
{
QDesktopServices::openUrl(SettingsCache::instance().getUpdateReleaseChannel()->getManualDownloadUrl());
}
void DlgUpdate::downloadUpdate(const QString &releaseName)
{
setLabel(tr("Downloading update: %1").arg(releaseName));
addStopDownloadAndRemoveOthers(true); // Will remove all other buttons
uDownloader->beginDownload(updateUrl);
}
void DlgUpdate::cancelDownload()
{
emit uDownloader->stopDownload();
setLabel("Download canceled");
addStopDownloadAndRemoveOthers(false);
downloadProgressMade(0, 1);
}
void DlgUpdate::beginUpdateCheck()
{
progress->setMinimum(0);
progress->setMaximum(0);
setLabel(tr("Checking for updates..."));
auto checker = new ClientUpdateChecker(this);
connect(checker, &ClientUpdateChecker::finishedCheck, this, &DlgUpdate::finishedUpdateCheck);
connect(checker, &ClientUpdateChecker::error, this, &DlgUpdate::updateCheckError);
checker->check();
}
void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Release *release)
{
QString publishDate, versionName;
// Update the UI to say we've finished
progress->setMaximum(100);
setLabel(tr("Finished checking for updates"));
// If there are no available builds, then they can't auto update.
enableUpdateButton(isCompatible);
if (isCompatible) {
// If there is an update, save its URL and work out its name
updateUrl = release->getDownloadUrl();
}
// Give the user the appropriate message
if (!needToUpdate) {
// If there's no need to update, tell them that. However we still allow them to run the
// downloader themselves if there's a compatible build
QMessageBox::information(
this, tr("No Update Available"),
tr("Cockatrice is up to date!") + "<br><br>" +
tr("You are already running the latest version available in the chosen release channel.") + "<br>" +
"<b>" + tr("Current version") + QString(":</b> %1<br>").arg(VERSION_STRING) + "<b>" +
tr("Selected release channel") +
QString(":</b> %1").arg(tr(SettingsCache::instance().getUpdateReleaseChannel()->getName().toUtf8())));
return;
}
publishDate = release->getPublishDate().toString(QLocale().dateFormat(QLocale::LongFormat));
if (isCompatible) {
int reply;
reply = QMessageBox::question(
this, tr("Update Available"),
tr("A new version of Cockatrice is available!") + "<br><br>" + "<b>" + tr("New version") +
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
"</a>)<br><br>" + tr("Do you want to update now?"),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes)
downloadUpdate(release->getName());
} else {
QMessageBox::information(
this, tr("Update Available"),
tr("A new version of Cockatrice is available!") + "<br><br>" + "<b>" + tr("New version") +
QString(":</b> %1<br>").arg(release->getName()) + "<b>" + tr("Released") +
QString(":</b> %1 (<a href=\"%2\">").arg(publishDate, release->getDescriptionUrl()) + tr("Changelog") +
"</a>)<br><br>" +
tr("Unfortunately, the automatic updater failed to find a compatible download. \nYou may have to "
"manually download the new version.") +
"<br><br>" +
tr("Please check the <a href=\"%1\">releases page</a> on our Github and download the build for your "
"system.")
.arg(release->getDescriptionUrl()));
}
}
void DlgUpdate::enableUpdateButton(bool enable)
{
manualDownload->setEnabled(enable);
}
void DlgUpdate::addStopDownloadAndRemoveOthers(bool enable)
{
if (enable) {
buttonBox->addButton(stopDownload, QDialogButtonBox::ActionRole);
buttonBox->removeButton(manualDownload);
buttonBox->removeButton(gotoDownload);
} else {
buttonBox->removeButton(stopDownload);
buttonBox->addButton(manualDownload, QDialogButtonBox::ActionRole);
buttonBox->addButton(gotoDownload, QDialogButtonBox::ActionRole);
}
}
void DlgUpdate::enableOkButton(bool enable)
{
ok->setEnabled(enable);
}
void DlgUpdate::setLabel(const QString &newText)
{
statusLabel->setText(newText);
}
void DlgUpdate::updateCheckError(const QString &errorString)
{
setLabel(tr("Error"));
QMessageBox::critical(this, tr("Update Error"),
tr("An error occurred while checking for updates:") + QString(" ") + errorString);
}
void DlgUpdate::downloadError(const QString &errorString)
{
setLabel(tr("Error"));
enableUpdateButton(true);
QMessageBox::critical(this, tr("Update Error"),
tr("An error occurred while downloading an update:") + QString(" ") + errorString);
}
void DlgUpdate::downloadSuccessful(const QUrl &filepath)
{
setLabel(tr("Installing..."));
// Try to open the installer. If it opens, quit Cockatrice
if (QDesktopServices::openUrl(filepath)) {
QMetaObject::invokeMethod(static_cast<MainWindow *>(parent()), "close", Qt::QueuedConnection);
qCInfo(DlgUpdateLog) << "Opened downloaded update file successfully - closing Cockatrice";
close();
} else {
setLabel(tr("Error"));
QMessageBox::critical(this, tr("Update Error"),
tr("Cockatrice is unable to open the installer.") + "<br><br>" +
tr("Try to update manually by closing Cockatrice and running the installer.") +
"<br>" + tr("Download location") + QString(": %1").arg(filepath.toLocalFile()));
}
}
void DlgUpdate::downloadProgressMade(qint64 bytesRead, qint64 totalBytes)
{
progress->setMaximum(totalBytes);
progress->setValue(bytesRead);
}

View file

@ -0,0 +1,53 @@
/**
* @file dlg_update.h
* @ingroup ClientUpdateDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_UPDATE_H
#define DLG_UPDATE_H
#include "../client/network/update/client/update_downloader.h"
#include <QDialogButtonBox>
#include <QLoggingCategory>
#include <QProgressDialog>
#include <QtNetwork>
inline Q_LOGGING_CATEGORY(DlgUpdateLog, "dlg_update");
class Release;
class DlgUpdate : public QDialog
{
Q_OBJECT
public:
explicit DlgUpdate(QWidget *parent);
private slots:
void finishedUpdateCheck(bool needToUpdate, bool isCompatible, Release *release);
void gotoDownloadPage();
void downloadUpdate(const QString &releaseName);
void cancelDownload();
void updateCheckError(const QString &errorString);
void downloadSuccessful(const QUrl &filepath);
void downloadProgressMade(qint64 bytesRead, qint64 totalBytes);
void downloadError(const QString &errorString);
void closeDialog();
private:
QUrl updateUrl;
void enableUpdateButton(bool enable);
void enableOkButton(bool enable);
void addStopDownloadAndRemoveOthers(bool enable);
void beginUpdateCheck();
void setLabel(const QString &text);
QLabel *statusLabel, *descriptionLabel;
QProgressBar *progress;
QPushButton *manualDownload, *gotoDownload, *ok, *stopDownload;
QPushButton *cancel;
UpdateDownloader *uDownloader;
QDialogButtonBox *buttonBox;
};
#endif

View file

@ -0,0 +1,84 @@
#include "dlg_view_log.h"
#include <QClipboard>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QRegularExpression>
#include <QVBoxLayout>
#include <libcockatrice/settings/cache_settings.h>
#include <libcockatrice/utility/logger.h>
DlgViewLog::DlgViewLog(QWidget *parent) : QDialog(parent)
{
logArea = new QPlainTextEdit;
logArea->setReadOnly(true);
auto *mainLayout = new QVBoxLayout;
mainLayout->setSpacing(3);
mainLayout->setContentsMargins(20, 20, 20, 6);
mainLayout->addWidget(logArea);
auto *bottomLayout = new QHBoxLayout;
coClearLog = new QCheckBox;
coClearLog->setText(tr("Clear log when closing"));
coClearLog->setChecked(SettingsCache::instance().servers().getClearDebugLogStatus(false));
connect(coClearLog, &QCheckBox::toggled, this, &DlgViewLog::actCheckBoxChanged);
copyToClipboardButton = new QPushButton;
copyToClipboardButton->setText(tr("Copy to clipboard"));
copyToClipboardButton->setAutoDefault(false);
connect(copyToClipboardButton, &QPushButton::clicked, this, &DlgViewLog::actCopyToClipboard);
bottomLayout->addWidget(coClearLog);
bottomLayout->addStretch();
bottomLayout->addWidget(copyToClipboardButton);
mainLayout->addLayout(bottomLayout);
setLayout(mainLayout);
setWindowTitle(tr("Debug Log"));
resize(800, 500);
loadInitialLogBuffer();
connect(&Logger::getInstance(), &Logger::logEntryAdded, this, &DlgViewLog::appendLogEntry);
}
void DlgViewLog::actCheckBoxChanged(bool abNewValue)
{
SettingsCache::instance().servers().setClearDebugLogStatus(abNewValue);
}
void DlgViewLog::actCopyToClipboard()
{
QApplication::clipboard()->setText(logArea->toPlainText());
}
void DlgViewLog::loadInitialLogBuffer()
{
QList<QString> logBuffer = Logger::getInstance().getLogBuffer();
for (const QString &message : logBuffer)
appendLogEntry(message);
}
void DlgViewLog::appendLogEntry(const QString &message)
{
static auto colorEscapeCodePattern = QRegularExpression("\033\\[\\d+m");
QString sanitizedMessage = message;
sanitizedMessage.replace(colorEscapeCodePattern, "");
logArea->appendPlainText(sanitizedMessage);
}
void DlgViewLog::closeEvent(QCloseEvent * /* event */)
{
if (coClearLog->isChecked()) {
logArea->clear();
logArea->appendPlainText(Logger::getInstance().getClientVersion());
logArea->appendPlainText(Logger::getInstance().getSystemArchitecture());
}
}

View file

@ -0,0 +1,37 @@
/**
* @file dlg_view_log.h
* @ingroup ServerLogDialogs
* @brief TODO: Document this.
*/
#ifndef DLG_VIEWLOG_H
#define DLG_VIEWLOG_H
#include <QCheckBox>
#include <QDialog>
class QPlainTextEdit;
class QCloseEvent;
class DlgViewLog : public QDialog
{
Q_OBJECT
public:
explicit DlgViewLog(QWidget *parent);
protected:
void closeEvent(QCloseEvent *event) override;
private:
QPlainTextEdit *logArea;
QCheckBox *coClearLog;
QPushButton *copyToClipboardButton;
void loadInitialLogBuffer();
private slots:
void appendLogEntry(const QString &message);
void actCheckBoxChanged(bool abNewValue);
void actCopyToClipboard();
};
#endif

View file

@ -0,0 +1,103 @@
#include "tip_of_the_day.h"
#include <QDate>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QXmlStreamReader>
#include <utility>
#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<TipOfTheDay>;
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;
}
auto readerName = reader.name().toString();
if (readerName == "tip") {
QString title, content, imagePath;
QDate date;
reader.readNext();
while (!reader.atEnd()) {
if (reader.readNext() == QXmlStreamReader::EndElement) {
break;
}
readerName = reader.name().toString();
if (readerName == "title") {
title = reader.readElementText();
} else if (readerName == "text") {
content = reader.readElementText();
} else if (readerName == "image") {
imagePath = "theme:tips/images/" + reader.readElementText();
} else if (readerName == "date") {
date = QDate::fromString(reader.readElementText(), Qt::ISODate);
} else {
// unknown 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();
}

View file

@ -0,0 +1,61 @@
/**
* @file tip_of_the_day.h
* @ingroup Dialogs
* @brief TODO: Document this.
*/
#ifndef TIP_OF_DAY_H
#define TIP_OF_DAY_H
#include <QAbstractListModel>
#include <QDate>
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<TipOfTheDay> *tipList;
};
#endif