diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 2555d66f..8d15ed98 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -99,6 +99,12 @@ SET(cockatrice_SOURCES src/sequenceEdit/sequenceedit.cpp src/sequenceEdit/shortcutstab.cpp src/lineeditcompleter.cpp + src/settings/settingsmanager.cpp + src/settings/carddatabasesettings.cpp + src/settings/serverssettings.cpp + src/settings/messagesettings.cpp + src/settings/gamefilterssettings.cpp + src/settings/layoutssettings.cpp ${VERSION_STRING_CPP} ) @@ -328,3 +334,8 @@ Data = Resources\") install(FILES ${WIN32SSLRUNTIME_LIBRARIES} DESTINATION ./) endif() endif() +#Compile a portable version, default off +option(PORTABLE "portable build" OFF) +IF(PORTABLE) +add_definitions(-DPORTABLE_BUILD) +endif() diff --git a/cockatrice/src/abstractclient.cpp b/cockatrice/src/abstractclient.cpp index 6faf6b33..a91ea784 100644 --- a/cockatrice/src/abstractclient.cpp +++ b/cockatrice/src/abstractclient.cpp @@ -19,6 +19,7 @@ #include "get_pb_extension.h" #include #include "client_metatypes.h" +#include "featureset.h" AbstractClient::AbstractClient(QObject *parent) : QObject(parent), nextCmdId(0), status(StatusDisconnected) @@ -45,6 +46,10 @@ AbstractClient::AbstractClient(QObject *parent) qRegisterMetaType("ServerInfo_User"); qRegisterMetaType >("QList"); qRegisterMetaType("Event_ReplayAdded"); + qRegisterMetaType >("missingFeatures"); + + FeatureSet features; + features.initalizeFeatureList(clientFeatures); connect(this, SIGNAL(sigQueuePendingCommand(PendingCommand *)), this, SLOT(queuePendingCommand(PendingCommand *))); } diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index 939066bc..9c7606a2 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -25,6 +25,7 @@ class Event_NotifyUser; class Event_ConnectionClosed; class Event_ServerShutdown; class Event_ReplayAdded; +class FeatureSet; enum ClientStatus { StatusDisconnected, @@ -96,6 +97,8 @@ public: static PendingCommand *prepareRoomCommand(const ::google::protobuf::Message &cmd, int roomId); static PendingCommand *prepareModeratorCommand(const ::google::protobuf::Message &cmd); static PendingCommand *prepareAdminCommand(const ::google::protobuf::Message &cmd); + + QMap clientFeatures; }; #endif diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 8978e70c..8b6da7e0 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -52,46 +51,29 @@ QString CardSet::getCorrectedShortName() const return invalidFileNames.contains(shortName) ? shortName + "_" : shortName; } +void CardSet::loadSetOptions() +{ + sortKey = settingsCache->cardDatabase().getSortKey(shortName); + enabled = settingsCache->cardDatabase().isEnabled(shortName); + isknown = settingsCache->cardDatabase().isKnown(shortName); +} + void CardSet::setSortKey(unsigned int _sortKey) { sortKey = _sortKey; - - QSettings settings; - settings.beginGroup("sets"); - settings.beginGroup(shortName); - settings.setValue("sortkey", sortKey); -} - -void CardSet::loadSetOptions() -{ - QSettings settings; - settings.beginGroup("sets"); - settings.beginGroup(shortName); - - sortKey = settings.value("sortkey", 0).toInt(); - enabled = settings.value("enabled", false).toBool(); - isknown = settings.value("isknown", false).toBool(); - // qDebug() << "load set" << shortName << "key" << sortKey; + settingsCache->cardDatabase().setSortKey(shortName,_sortKey); } void CardSet::setEnabled(bool _enabled) { enabled = _enabled; - - QSettings settings; - settings.beginGroup("sets"); - settings.beginGroup(shortName); - settings.setValue("enabled", enabled); + settingsCache->cardDatabase().setEnabled(shortName,_enabled); } void CardSet::setIsKnown(bool _isknown) { isknown = _isknown; - - QSettings settings; - settings.beginGroup("sets"); - settings.beginGroup(shortName); - settings.setValue("isknown", isknown); + settingsCache->cardDatabase().setIsKnown(shortName,_isknown); } class SetList::KeyCompareFunctor { @@ -1255,4 +1237,4 @@ bool CardDatabase::hasDetectedFirstRun() } return false; -} \ No newline at end of file +} diff --git a/cockatrice/src/client_metatypes.h b/cockatrice/src/client_metatypes.h index db1c90f7..d0ece007 100644 --- a/cockatrice/src/client_metatypes.h +++ b/cockatrice/src/client_metatypes.h @@ -24,6 +24,6 @@ Q_DECLARE_METATYPE(Event_UserMessage) Q_DECLARE_METATYPE(ServerInfo_User) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(Event_ReplayAdded) - +Q_DECLARE_METATYPE(QList) #endif diff --git a/cockatrice/src/dlg_connect.cpp b/cockatrice/src/dlg_connect.cpp index c97e4e6d..13cf5480 100644 --- a/cockatrice/src/dlg_connect.cpp +++ b/cockatrice/src/dlg_connect.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -11,25 +10,23 @@ #include #include #include "dlg_connect.h" +#include "settingscache.h" DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent) { - QSettings settings; - settings.beginGroup("server"); - previousHostButton = new QRadioButton(tr("Previous Host"), this); - previousHosts = new QComboBox(this); previousHosts->installEventFilter(new DeleteHighlightedItemWhenShiftDelPressedEventFilter); - QStringList previousHostList = settings.value("previoushosts").toStringList(); + + QStringList previousHostList = settingsCache->servers().getPreviousHostList(); if (previousHostList.isEmpty()) { previousHostList << "cockatrice.woogerworks.com"; previousHostList << "vps.poixen.com"; previousHostList << "chickatrice.net"; } previousHosts->addItems(previousHostList); - previousHosts->setCurrentIndex(settings.value("previoushostindex").toInt()); + previousHosts->setCurrentIndex(settingsCache->servers().getPrevioushostindex()); newHostButton = new QRadioButton(tr("New Host"), this); @@ -39,28 +36,28 @@ DlgConnect::DlgConnect(QWidget *parent) hostLabel->setBuddy(hostEdit); portLabel = new QLabel(tr("&Port:")); - portEdit = new QLineEdit(settings.value("port", "4747").toString()); + portEdit = new QLineEdit(settingsCache->servers().getPort("4747")); portLabel->setBuddy(portEdit); playernameLabel = new QLabel(tr("Player &name:")); - playernameEdit = new QLineEdit(settings.value("playername", "Player").toString()); + playernameEdit = new QLineEdit(settingsCache->servers().getPlayerName("Player")); playernameLabel->setBuddy(playernameEdit); passwordLabel = new QLabel(tr("P&assword:")); - passwordEdit = new QLineEdit(settings.value("password").toString()); + passwordEdit = new QLineEdit(settingsCache->servers().getPassword()); passwordLabel->setBuddy(passwordEdit); passwordEdit->setEchoMode(QLineEdit::Password); savePasswordCheckBox = new QCheckBox(tr("&Save password")); - savePasswordCheckBox->setChecked(settings.value("save_password", 1).toInt()); + savePasswordCheckBox->setChecked(settingsCache->servers().getSavePassword()); autoConnectCheckBox = new QCheckBox(tr("A&uto connect at start")); if(savePasswordCheckBox->isChecked()) { - autoConnectCheckBox->setChecked(settings.value("auto_connect", 0).toInt()); + autoConnectCheckBox->setChecked(settingsCache->servers().getAutoConnect()); autoConnectCheckBox->setEnabled(true); } else { - settings.setValue("auto_connect", 0); + settingsCache->servers().setAutoConnect(0); autoConnectCheckBox->setChecked(0); autoConnectCheckBox->setEnabled(false); } @@ -98,7 +95,7 @@ DlgConnect::DlgConnect(QWidget *parent) connect(previousHostButton, SIGNAL(toggled(bool)), this, SLOT(previousHostSelected(bool))); connect(newHostButton, SIGNAL(toggled(bool)), this, SLOT(newHostSelected(bool))); - if (settings.value("previoushostlogin", 1).toInt()) + if (settingsCache->servers().getPreviousHostLogin()) previousHostButton->setChecked(true); else newHostButton->setChecked(true); @@ -133,14 +130,12 @@ void DlgConnect::passwordSaved(int state) void DlgConnect::actOk() { - QSettings settings; - settings.beginGroup("server"); - settings.setValue("port", portEdit->text()); - settings.setValue("playername", playernameEdit->text()); - settings.setValue("password", savePasswordCheckBox->isChecked() ? passwordEdit->text() : QString()); - settings.setValue("save_password", savePasswordCheckBox->isChecked() ? 1 : 0); - settings.setValue("auto_connect", autoConnectCheckBox->isChecked() ? 1 : 0); - settings.setValue("previoushostlogin", previousHostButton->isChecked() ? 1 : 0); + settingsCache->servers().setPort(portEdit->text()); + settingsCache->servers().setPlayerName(playernameEdit->text()); + settingsCache->servers().setPassword(savePasswordCheckBox->isChecked() ? passwordEdit->text() : QString()); + settingsCache->servers().setSavePassword(savePasswordCheckBox->isChecked() ? 1 : 0); + settingsCache->servers().setAutoConnect(autoConnectCheckBox->isChecked() ? 1 : 0); + settingsCache->servers().setPreviousHostLogin(previousHostButton->isChecked() ? 1 : 0); QStringList hostList; if (newHostButton->isChecked()) @@ -151,9 +146,8 @@ void DlgConnect::actOk() if(!previousHosts->itemText(i).trimmed().isEmpty()) hostList << previousHosts->itemText(i); - settings.setValue("previoushosts", hostList); - settings.setValue("previoushostindex", previousHosts->currentIndex()); - settings.endGroup(); + settingsCache->servers().setPreviousHostList(hostList); + settingsCache->servers().setPrevioushostindex(previousHosts->currentIndex()); accept(); } @@ -165,12 +159,8 @@ QString DlgConnect::getHost() const { void DlgConnect::actCancel() { - QSettings settings; - settings.beginGroup("server"); - settings.setValue("save_password", savePasswordCheckBox->isChecked() ? 1 : 0); - settings.setValue("auto_connect", autoConnectCheckBox->isChecked() ? 1 : 0); - settings.endGroup(); - + settingsCache->servers().setSavePassword(savePasswordCheckBox->isChecked() ? 1 : 0); + settingsCache->servers().setAutoConnect( autoConnectCheckBox->isChecked() ? 1 : 0); reject(); } diff --git a/cockatrice/src/dlg_edit_password.cpp b/cockatrice/src/dlg_edit_password.cpp index 729b8974..7637e208 100644 --- a/cockatrice/src/dlg_edit_password.cpp +++ b/cockatrice/src/dlg_edit_password.cpp @@ -3,21 +3,19 @@ #include #include #include -#include +#include "settingscache.h" #include "dlg_edit_password.h" DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent) { - QSettings settings; - settings.beginGroup("server"); oldPasswordLabel = new QLabel(tr("Old password:")); oldPasswordEdit = new QLineEdit(); - if(settings.value("save_password", 1).toInt()) - oldPasswordEdit->setText(settings.value("password").toString()); + if(settingsCache->servers().getSavePassword()) + oldPasswordEdit->setText(settingsCache->servers().getPassword()); oldPasswordLabel->setBuddy(oldPasswordEdit); oldPasswordEdit->setEchoMode(QLineEdit::Password); @@ -62,12 +60,8 @@ void DlgEditPassword::actOk() return; } - QSettings settings; - settings.beginGroup("server"); // always save the password so it will be picked up by the connect dialog - settings.setValue("password", newPasswordEdit->text()); - settings.endGroup(); - + settingsCache->servers().setPassword(newPasswordEdit->text()); accept(); } diff --git a/cockatrice/src/dlg_edit_user.cpp b/cockatrice/src/dlg_edit_user.cpp index fd5df607..570a1058 100644 --- a/cockatrice/src/dlg_edit_user.cpp +++ b/cockatrice/src/dlg_edit_user.cpp @@ -1,4 +1,3 @@ -#include #include #include #include diff --git a/cockatrice/src/dlg_filter_games.cpp b/cockatrice/src/dlg_filter_games.cpp index 28f2c8d7..ff02dcc6 100644 --- a/cockatrice/src/dlg_filter_games.cpp +++ b/cockatrice/src/dlg_filter_games.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include DlgFilterGames::DlgFilterGames(const QMap &_allGameTypes, const GamesProxyModel *_gamesProxyModel, QWidget *parent) @@ -17,9 +16,6 @@ DlgFilterGames::DlgFilterGames(const QMap &_allGameTypes, const Ga allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel) { - QSettings settings; - settings.beginGroup("filter_games"); - unavailableGamesVisibleCheckBox = new QCheckBox(tr("Show &unavailable games")); unavailableGamesVisibleCheckBox->setChecked(gamesProxyModel->getUnavailableGamesVisible()); diff --git a/cockatrice/src/dlg_register.cpp b/cockatrice/src/dlg_register.cpp index 97f47c9d..f97a954d 100644 --- a/cockatrice/src/dlg_register.cpp +++ b/cockatrice/src/dlg_register.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -14,23 +13,20 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent) { - QSettings settings; - settings.beginGroup("server"); - hostLabel = new QLabel(tr("&Host:")); - hostEdit = new QLineEdit(settings.value("hostname", "cockatrice.woogerworks.com").toString()); + hostEdit = new QLineEdit(settingsCache->servers().getHostname("cockatrice.woogerworks.com")); hostLabel->setBuddy(hostEdit); - portLabel = new QLabel(tr("&Port:")); - portEdit = new QLineEdit(settings.value("port", "4747").toString()); + portLabel = new QLabel(tr("&Port:")); + portEdit = new QLineEdit(settingsCache->servers().getPort("4747")); portLabel->setBuddy(portEdit); - playernameLabel = new QLabel(tr("Player &name:")); - playernameEdit = new QLineEdit(settings.value("playername", "Player").toString()); + playernameLabel = new QLabel(tr("Player &name:")); + playernameEdit = new QLineEdit(settingsCache->servers().getPlayerName("Player")); playernameLabel->setBuddy(playernameEdit); - passwordLabel = new QLabel(tr("P&assword:")); - passwordEdit = new QLineEdit(settings.value("password").toString()); + passwordLabel = new QLabel(tr("P&assword:")); + passwordEdit = new QLineEdit(settingsCache->servers().getPassword()); passwordLabel->setBuddy(passwordEdit); passwordEdit->setEchoMode(QLineEdit::Password); @@ -366,14 +362,11 @@ void DlgRegister::actOk() return; } - QSettings settings; - settings.beginGroup("server"); - settings.setValue("hostname", hostEdit->text()); - settings.setValue("port", portEdit->text()); - settings.setValue("playername", playernameEdit->text()); + settingsCache->servers().setHostName(hostEdit->text()); + settingsCache->servers().setPort(portEdit->text()); + settingsCache->servers().setPlayerName(playernameEdit->text()); // always save the password so it will be picked up by the connect dialog - settings.setValue("password", passwordEdit->text()); - settings.endGroup(); + settingsCache->servers().setPassword(passwordEdit->text()); accept(); } diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index 5b18f7ed..05e748dd 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -46,6 +45,7 @@ GeneralSettingsPage::GeneralSettingsPage() picDownloadCheckBox.setChecked(settingsCache->getPicDownload()); picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq()); + updateNotificationCheckBox.setChecked(settingsCache->getNotifyAboutUpdates()); pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN); // 2047 is the max value to avoid overflowing of QPixmapCache::setCacheLimit(int size) @@ -65,19 +65,21 @@ GeneralSettingsPage::GeneralSettingsPage() connect(&picDownloadHqCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownloadHq(int))); connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int))); connect(&picDownloadHqCheckBox, SIGNAL(clicked(bool)), this, SLOT(setEnabledStatus(bool))); + connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int))); connect(highQualityURLEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrlHq(QString))); QGridLayout *personalGrid = new QGridLayout; personalGrid->addWidget(&languageLabel, 0, 0); personalGrid->addWidget(&languageBox, 0, 1); - personalGrid->addWidget(&pixmapCacheLabel, 1, 0, 1, 1); - personalGrid->addWidget(&pixmapCacheEdit, 1, 1, 1, 1); - personalGrid->addWidget(&picDownloadCheckBox, 2, 0, 1, 2); - personalGrid->addWidget(&picDownloadHqCheckBox, 3, 0, 1, 2); - personalGrid->addWidget(&clearDownloadedPicsButton, 4, 0, 1, 1); - personalGrid->addWidget(&highQualityURLLabel, 5, 0, 1, 1); - personalGrid->addWidget(highQualityURLEdit, 5, 1, 1, 1); - personalGrid->addWidget(&highQualityURLLinkLabel, 6, 1, 1, 1); + personalGrid->addWidget(&pixmapCacheLabel, 1, 0); + personalGrid->addWidget(&pixmapCacheEdit, 1, 1); + personalGrid->addWidget(&updateNotificationCheckBox, 2, 0); + personalGrid->addWidget(&picDownloadCheckBox, 3, 0); + personalGrid->addWidget(&picDownloadHqCheckBox, 4, 0); + personalGrid->addWidget(&highQualityURLLabel, 5, 0); + personalGrid->addWidget(highQualityURLEdit, 5, 1); + personalGrid->addWidget(&highQualityURLLinkLabel, 6, 1); + personalGrid->addWidget(&clearDownloadedPicsButton, 6, 0); highQualityURLLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse); highQualityURLLinkLabel.setOpenExternalLinks(true); @@ -247,6 +249,7 @@ void GeneralSettingsPage::retranslateUi() highQualityURLLabel.setText(tr("Custom Card Download URL:")); highQualityURLLinkLabel.setText(QString("%2").arg(LINKING_FAQ_URL).arg(tr("Linking FAQ"))); clearDownloadedPicsButton.setText(tr("Reset/Clear Downloaded Pictures")); + updateNotificationCheckBox.setText(tr("Notify when new client features are available")); } void GeneralSettingsPage::setEnabledStatus(bool status) @@ -512,12 +515,11 @@ MessagesSettingsPage::MessagesSettingsPage() highlightGroupBox = new QGroupBox; highlightGroupBox->setLayout(highlightNotice); - QSettings settings; messageList = new QListWidget; - settings.beginGroup("messages"); - int count = settings.value("count", 0).toInt(); + + int count = settingsCache->messages().getCount(); for (int i = 0; i < count; i++) - messageList->addItem(settings.value(QString("msg%1").arg(i)).toString()); + messageList->addItem(settingsCache->messages().getMessageAt(i)); aAdd = new QAction(this); aAdd->setIcon(QIcon("theme:icons/increment.svg")); @@ -589,11 +591,9 @@ void MessagesSettingsPage::updateHighlightPreview() { void MessagesSettingsPage::storeSettings() { - QSettings settings; - settings.beginGroup("messages"); - settings.setValue("count", messageList->count()); + settingsCache->messages().setCount(messageList->count()); for (int i = 0; i < messageList->count(); i++) - settings.setValue(QString("msg%1").arg(i), messageList->item(i)->text()); + settingsCache->messages().setMessageAt(i, messageList->item(i)->text()); } void MessagesSettingsPage::actAdd() @@ -918,3 +918,4 @@ void DlgSettings::retranslateUi() for (int i = 0; i < pagesWidget->count(); i++) dynamic_cast(pagesWidget->widget(i))->retranslateUi(); } + diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 2bceda71..45443c0b 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -60,6 +60,7 @@ private: QComboBox languageBox; QCheckBox picDownloadCheckBox; QCheckBox picDownloadHqCheckBox; + QCheckBox updateNotificationCheckBox; QLabel languageLabel; QLabel pixmapCacheLabel; QLabel deckPathLabel; diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp index d88fafbe..0e537fee 100644 --- a/cockatrice/src/gamesmodel.cpp +++ b/cockatrice/src/gamesmodel.cpp @@ -1,12 +1,12 @@ #include "gamesmodel.h" #include "pb/serverinfo_game.pb.h" #include "pixmapgenerator.h" +#include "settingscache.h" + #include #include #include #include -#include -#include enum GameListColumn {ROOM, CREATED, DESCRIPTION, CREATOR, GAME_TYPE, RESTRICTIONS, PLAYERS, SPECTATORS}; @@ -283,19 +283,17 @@ void GamesProxyModel::resetFilterParameters() void GamesProxyModel::loadFilterParameters(const QMap &allGameTypes) { - QSettings settings; - settings.beginGroup("filter_games"); - unavailableGamesVisible = settings.value("unavailable_games_visible", false).toBool(); - showPasswordProtectedGames = settings.value("show_password_protected_games", true).toBool(); - gameNameFilter = settings.value("game_name_filter", "").toString(); - maxPlayersFilterMin = settings.value("min_players", 1).toInt(); - maxPlayersFilterMax = settings.value("max_players", DEFAULT_MAX_PLAYERS_MAX).toInt(); + unavailableGamesVisible = settingsCache->gameFilters().isUnavailableGamesVisible(); + showPasswordProtectedGames = settingsCache->gameFilters().isShowPasswordProtectedGames(); + gameNameFilter = settingsCache->gameFilters().getGameNameFilter(); + maxPlayersFilterMin = settingsCache->gameFilters().getMinPlayers(); + maxPlayersFilterMax = settingsCache->gameFilters().getMaxPlayers(); QMapIterator gameTypesIterator(allGameTypes); while (gameTypesIterator.hasNext()) { gameTypesIterator.next(); - if (settings.value("game_type/" + hashGameType(gameTypesIterator.value()), false).toBool()) { + if (settingsCache->gameFilters().isGameTypeEnabled(gameTypesIterator.value())){ gameTypeFilter.insert(gameTypesIterator.key()); } } @@ -305,28 +303,19 @@ void GamesProxyModel::loadFilterParameters(const QMap &allGameType void GamesProxyModel::saveFilterParameters(const QMap &allGameTypes) { - QSettings settings; - settings.beginGroup("filter_games"); - - settings.setValue("unavailable_games_visible", unavailableGamesVisible); - settings.setValue( - "show_password_protected_games", - showPasswordProtectedGames - ); - settings.setValue("game_name_filter", gameNameFilter); + settingsCache->gameFilters().setUnavailableGamesVisible(unavailableGamesVisible); + settingsCache->gameFilters().setShowPasswordProtectedGames(showPasswordProtectedGames); + settingsCache->gameFilters().setGameNameFilter(gameNameFilter); QMapIterator gameTypeIterator(allGameTypes); while (gameTypeIterator.hasNext()) { gameTypeIterator.next(); - - settings.setValue( - "game_type/" + hashGameType(gameTypeIterator.value()), - gameTypeFilter.contains(gameTypeIterator.key()) - ); + bool enabled = gameTypeFilter.contains(gameTypeIterator.key()); + settingsCache->gameFilters().setGameTypeEnabled(gameTypeIterator.value(),enabled); } - settings.setValue("min_players", maxPlayersFilterMin); - settings.setValue("max_players", maxPlayersFilterMax); + settingsCache->gameFilters().setMinPlayers(maxPlayersFilterMin); + settingsCache->gameFilters().setMaxPlayers(maxPlayersFilterMax); } bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sourceParent*/) const @@ -367,7 +356,3 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sourc return true; } - -QString GamesProxyModel::hashGameType(const QString &gameType) const { - return QCryptographicHash::hash(gameType.toUtf8(), QCryptographicHash::Md5).toHex(); -} diff --git a/cockatrice/src/gamesmodel.h b/cockatrice/src/gamesmodel.h index df252958..97d31b94 100644 --- a/cockatrice/src/gamesmodel.h +++ b/cockatrice/src/gamesmodel.h @@ -52,13 +52,7 @@ private: QSet gameTypeFilter; int maxPlayersFilterMin, maxPlayersFilterMax; - static const int DEFAULT_MAX_PLAYERS_MAX = 99; - - /* - * The game type might contain special characters, so to use it in - * QSettings we just hash it. - */ - QString hashGameType(const QString &gameType) const; + static const int DEFAULT_MAX_PLAYERS_MAX = 99; public: GamesProxyModel(QObject *parent = 0, ServerInfo_User *_ownUser = 0); diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index d691659a..c6f303b6 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -34,7 +33,6 @@ #include #include "QtNetwork/QNetworkInterface" #include - #include "main.h" #include "window_main.h" #include "dlg_settings.h" @@ -44,6 +42,7 @@ #include "pixmapgenerator.h" #include "rng_sfmt.h" #include "soundengine.h" +#include "featureset.h" //Q_IMPORT_PLUGIN(qjpeg) @@ -156,11 +155,15 @@ int main(int argc, char *argv[]) installNewTranslator(); qsrand(QDateTime::currentDateTime().toTime_t()); - + +#ifdef PORTABLE_BUILD + const QString dataDir = "data/"; +#else #if QT_VERSION < 0x050000 const QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #else const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); +#endif #endif if (!db->getLoadSuccess()) if (!db->loadCardDatabase(dataDir + "/cards.xml")) diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index e1d68aa2..ca5ab211 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -21,7 +21,6 @@ #include "color.h" #include "deck_loader.h" #include "main.h" -#include #include #include #include @@ -826,12 +825,10 @@ void Player::initSayMenu() { sayMenu->clear(); - QSettings settings; - settings.beginGroup("messages"); - int count = settings.value("count", 0).toInt(); + int count = settingsCache->messages().getCount(); for (int i = 0; i < count; i++) { - QAction *newAction = new QAction(settings.value(QString("msg%1").arg(i)).toString(), this); + QAction *newAction = new QAction(settingsCache->messages().getMessageAt(i), this); if (i <= 10){ newAction->setShortcut(QKeySequence("Ctrl+" + QString::number((i + 1) % 10))); } diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index e149082b..b652726d 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -1,3 +1,4 @@ +#include #include #include #include "remoteclient.h" @@ -81,7 +82,6 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica cmdRegister.set_country(country.toStdString()); cmdRegister.set_real_name(realName.toStdString()); cmdRegister.set_clientid(settingsCache->getClientID().toStdString()); - PendingCommand *pend = prepareSessionCommand(cmdRegister); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(registerResponse(Response))); sendCommand(pend); @@ -105,8 +105,7 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica doLogin(); } -void RemoteClient::doLogin() -{ +void RemoteClient::doLogin() { setStatus(StatusLoggingIn); Command_Login cmdLogin; @@ -114,6 +113,13 @@ void RemoteClient::doLogin() cmdLogin.set_password(password.toStdString()); cmdLogin.set_clientid(settingsCache->getClientID().toStdString()); cmdLogin.set_clientver(VERSION_STRING); + + if (!clientFeatures.isEmpty()) { + QMap::iterator i; + for (i = clientFeatures.begin(); i != clientFeatures.end(); ++i) + cmdLogin.add_clientfeatures(i.key().toStdString().c_str()); + } + PendingCommand *pend = prepareSessionCommand(cmdLogin); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(loginResponse(Response))); sendCommand(pend); @@ -140,8 +146,17 @@ void RemoteClient::loginResponse(const Response &response) for (int i = resp.ignore_list_size() - 1; i >= 0; --i) ignoreList.append(resp.ignore_list(i)); emit ignoreListReceived(ignoreList); + + if (resp.missing_features_size() > 0 && settingsCache->getNotifyAboutUpdates()) + emit notifyUserAboutUpdate(); + } else { - emit loginError(response.response_code(), QString::fromStdString(resp.denied_reason_str()), resp.denied_end_time()); + QList missingFeatures; + if (resp.missing_features_size() > 0) { + for (int i = 0; i < resp.missing_features_size(); ++i) + missingFeatures << QString::fromStdString(resp.missing_features(i)); + } + emit loginError(response.response_code(), QString::fromStdString(resp.denied_reason_str()), resp.denied_end_time(), missingFeatures); setStatus(StatusDisconnecting); } } diff --git a/cockatrice/src/remoteclient.h b/cockatrice/src/remoteclient.h index c1478732..3e0ae971 100644 --- a/cockatrice/src/remoteclient.h +++ b/cockatrice/src/remoteclient.h @@ -11,7 +11,7 @@ class RemoteClient : public AbstractClient { signals: void maxPingTime(int seconds, int maxSeconds); void serverTimeout(); - void loginError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); + void loginError(Response::ResponseCode resp, QString reasonStr, quint32 endTime, QList missingFeatures); void registerError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); void activateError(); void socketError(const QString &errorString); @@ -21,6 +21,7 @@ signals: void sigRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); void sigActivateToServer(const QString &_token); void sigDisconnectFromServer(); + void notifyUserAboutUpdate(); private slots: void slotConnected(); void readData(); diff --git a/cockatrice/src/settings/carddatabasesettings.cpp b/cockatrice/src/settings/carddatabasesettings.cpp new file mode 100644 index 00000000..39b23bfc --- /dev/null +++ b/cockatrice/src/settings/carddatabasesettings.cpp @@ -0,0 +1,36 @@ +#include "carddatabasesettings.h" + +CardDatabaseSettings::CardDatabaseSettings(QString settingPath, QObject *parent) + : SettingsManager(settingPath+"cardDatabase.ini", parent) +{ +} + +void CardDatabaseSettings::setSortKey(QString shortName, unsigned int sortKey) +{ + setValue(sortKey,"sortkey", "sets", shortName); +} + +void CardDatabaseSettings::setEnabled(QString shortName, bool enabled) +{ + setValue(enabled, "enabled", "sets", shortName); +} + +void CardDatabaseSettings::setIsKnown(QString shortName, bool isknown) +{ + setValue(isknown, "isknown", "sets", shortName); +} + +unsigned int CardDatabaseSettings::getSortKey(QString shortName) +{ + return getValue("sortkey", "sets", shortName).toUInt(); +} + +bool CardDatabaseSettings::isEnabled(QString shortName) +{ + return getValue("enabled", "sets", shortName).toBool(); +} + +bool CardDatabaseSettings::isKnown(QString shortName) +{ + return getValue("isknown", "sets", shortName).toBool(); +} diff --git a/cockatrice/src/settings/carddatabasesettings.h b/cockatrice/src/settings/carddatabasesettings.h new file mode 100644 index 00000000..0f00d7dd --- /dev/null +++ b/cockatrice/src/settings/carddatabasesettings.h @@ -0,0 +1,34 @@ +#ifndef CARDDATABASESETTINGS_H +#define CARDDATABASESETTINGS_H + +#include "settingsmanager.h" + +#include +#include +#include + +class CardDatabaseSettings : public SettingsManager +{ + Q_OBJECT + friend class SettingsCache; +public: + void setSortKey(QString shortName, unsigned int sortKey); + void setEnabled(QString shortName, bool enabled); + void setIsKnown(QString shortName, bool isknown); + + unsigned int getSortKey(QString shortName); + bool isEnabled(QString shortName); + bool isKnown(QString shortName); +signals: + +public slots: + +private: + CardDatabaseSettings(QString settingPath, QObject *parent = 0); + CardDatabaseSettings( const CardDatabaseSettings& /*other*/ ); + CardDatabaseSettings( CardDatabaseSettings& /*other*/ ); + CardDatabaseSettings( volatile const CardDatabaseSettings& /*other*/ ); + CardDatabaseSettings( volatile CardDatabaseSettings& /*other*/ ); +}; + +#endif // CARDDATABASESETTINGS_H diff --git a/cockatrice/src/settings/gamefilterssettings.cpp b/cockatrice/src/settings/gamefilterssettings.cpp new file mode 100644 index 00000000..105924a4 --- /dev/null +++ b/cockatrice/src/settings/gamefilterssettings.cpp @@ -0,0 +1,88 @@ +#include "gamefilterssettings.h" +#include + +GameFiltersSettings::GameFiltersSettings(QString settingPath, QObject *parent) + : SettingsManager(settingPath+"gamefilters.ini", parent) +{ +} + +/* + * The game type might contain special characters, so to use it in + * QSettings we just hash it. + */ +QString GameFiltersSettings::hashGameType(const QString &gameType) const +{ + return QCryptographicHash::hash(gameType.toUtf8(), QCryptographicHash::Md5).toHex(); +} + +void GameFiltersSettings::setUnavailableGamesVisible(bool enabled) +{ + setValue(enabled, "unavailable_games_visible","filter_games"); +} + +bool GameFiltersSettings::isUnavailableGamesVisible() +{ + QVariant previous = getValue("unavailable_games_visible","filter_games"); + return previous == QVariant() ? false : previous.toBool(); +} + +void GameFiltersSettings::setShowPasswordProtectedGames(bool show) +{ + setValue(show, "show_password_protected_games","filter_games"); +} + +bool GameFiltersSettings::isShowPasswordProtectedGames() +{ + QVariant previous = getValue("show_password_protected_games","filter_games"); + return previous == QVariant() ? true : previous.toBool(); +} + +void GameFiltersSettings::setGameNameFilter(QString gameName) +{ + setValue(gameName, "game_name_filter","filter_games"); +} + +QString GameFiltersSettings::getGameNameFilter() +{ + return getValue("game_name_filter","filter_games").toString(); +} + +void GameFiltersSettings::setMinPlayers(int min) +{ + setValue(min, "min_players","filter_games"); +} + +int GameFiltersSettings::getMinPlayers() +{ + QVariant previous = getValue("min_players","filter_games"); + return previous == QVariant() ? 1 : previous.toInt(); +} + +void GameFiltersSettings::setMaxPlayers(int max) +{ + setValue(max, "max_players","filter_games"); +} + +int GameFiltersSettings::getMaxPlayers() +{ + QVariant previous = getValue("max_players","filter_games"); + return previous == QVariant() ? 99 : previous.toInt(); +} + +void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled) +{ + setValue(enabled, "game_type/"+hashGameType(gametype),"filter_games"); +} + +void GameFiltersSettings::setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled) +{ + setValue(enabled, gametypeHASHED,"filter_games"); +} + +bool GameFiltersSettings::isGameTypeEnabled(QString gametype) +{ + QVariant previous = getValue("game_type/"+hashGameType(gametype),"filter_games"); + return previous == QVariant() ? false : previous.toBool(); +} + + diff --git a/cockatrice/src/settings/gamefilterssettings.h b/cockatrice/src/settings/gamefilterssettings.h new file mode 100644 index 00000000..16035960 --- /dev/null +++ b/cockatrice/src/settings/gamefilterssettings.h @@ -0,0 +1,39 @@ +#ifndef GAMEFILTERSSETTINGS_H +#define GAMEFILTERSSETTINGS_H + +#include "settingsmanager.h" + +class GameFiltersSettings : public SettingsManager +{ + Q_OBJECT + friend class SettingsCache; +public: + bool isUnavailableGamesVisible(); + bool isShowPasswordProtectedGames(); + QString getGameNameFilter(); + int getMinPlayers(); + int getMaxPlayers(); + bool isGameTypeEnabled(QString gametype); + + void setUnavailableGamesVisible(bool enabled); + void setShowPasswordProtectedGames(bool show); + void setGameNameFilter(QString gameName); + void setMinPlayers(int min); + void setMaxPlayers(int max); + void setGameTypeEnabled(QString gametype, bool enabled); + void setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled); +signals: + +public slots: + +private: + GameFiltersSettings(QString settingPath,QObject *parent = 0); + GameFiltersSettings( const GameFiltersSettings& /*other*/ ); + GameFiltersSettings( GameFiltersSettings& /*other*/ ); + GameFiltersSettings( volatile const GameFiltersSettings& /*other*/ ); + GameFiltersSettings( volatile GameFiltersSettings& /*other*/ ); + + QString hashGameType(const QString &gameType) const; +}; + +#endif // GAMEFILTERSSETTINGS_H diff --git a/cockatrice/src/settings/layoutssettings.cpp b/cockatrice/src/settings/layoutssettings.cpp new file mode 100644 index 00000000..d81b2bcf --- /dev/null +++ b/cockatrice/src/settings/layoutssettings.cpp @@ -0,0 +1,59 @@ +#include "layoutssettings.h" + +LayoutsSettings::LayoutsSettings(QString settingPath, QObject *parent) + : SettingsManager(settingPath+"layouts.ini", parent) +{ +} + +const QByteArray LayoutsSettings::getDeckEditorLayoutState() +{ + return getValue("layouts/deckEditor_state").toByteArray(); +} + +void LayoutsSettings::setDeckEditorLayoutState(const QByteArray &value) +{ + setValue(value,"layouts/deckEditor_state"); +} + +const QByteArray LayoutsSettings::getDeckEditorGeometry() +{ + return getValue("layouts/deckEditor_geometry").toByteArray(); +} + +void LayoutsSettings::setDeckEditorGeometry(const QByteArray &value) +{ + setValue(value,"layouts/deckEditor_geometry"); +} + +const QSize LayoutsSettings::getDeckEditorCardSize() +{ + QVariant previous = getValue("layouts/deckEditor_CardSize"); + return previous == QVariant() ? QSize(250,500) : previous.toSize(); +} + +void LayoutsSettings::setDeckEditorCardSize(const QSize &value) +{ + setValue(value,"layouts/deckEditor_CardSize"); +} + +const QSize LayoutsSettings::getDeckEditorDeckSize() +{ + QVariant previous = getValue("layouts/deckEditor_DeckSize"); + return previous == QVariant() ? QSize(250,360) : previous.toSize(); +} + +void LayoutsSettings::setDeckEditorDeckSize(const QSize &value) +{ + setValue(value,"layouts/deckEditor_DeckSize"); +} + +const QSize LayoutsSettings::getDeckEditorFilterSize() +{ + QVariant previous = getValue("layouts/deckEditor_FilterSize"); + return previous == QVariant() ? QSize(250,250) : previous.toSize(); +} + +void LayoutsSettings::setDeckEditorFilterSize(const QSize &value) +{ + setValue(value,"layouts/deckEditor_FilterSize"); +} diff --git a/cockatrice/src/settings/layoutssettings.h b/cockatrice/src/settings/layoutssettings.h new file mode 100644 index 00000000..4a42586e --- /dev/null +++ b/cockatrice/src/settings/layoutssettings.h @@ -0,0 +1,36 @@ +#ifndef LAYOUTSSETTINGS_H +#define LAYOUTSSETTINGS_H + +#include "settingsmanager.h" +#include + +class LayoutsSettings : public SettingsManager +{ + Q_OBJECT + friend class SettingsCache; +public: + + void setDeckEditorLayoutState(const QByteArray &value); + void setDeckEditorGeometry(const QByteArray &value); + void setDeckEditorCardSize(const QSize &value); + void setDeckEditorDeckSize(const QSize &value); + void setDeckEditorFilterSize(const QSize &value); + + const QByteArray getDeckEditorLayoutState(); + const QByteArray getDeckEditorGeometry(); + const QSize getDeckEditorCardSize(); + const QSize getDeckEditorDeckSize(); + const QSize getDeckEditorFilterSize(); +signals: + +public slots: + +private: + LayoutsSettings(QString settingPath,QObject *parent = 0); + LayoutsSettings( const LayoutsSettings& /*other*/ ); + LayoutsSettings( LayoutsSettings& /*other*/ ); + LayoutsSettings( volatile const LayoutsSettings& /*other*/ ); + LayoutsSettings( volatile LayoutsSettings& /*other*/ ); +}; + +#endif // LAYOUTSSETTINGS_H diff --git a/cockatrice/src/settings/messagesettings.cpp b/cockatrice/src/settings/messagesettings.cpp new file mode 100644 index 00000000..fbcfc237 --- /dev/null +++ b/cockatrice/src/settings/messagesettings.cpp @@ -0,0 +1,26 @@ +#include "messagesettings.h" + +MessageSettings::MessageSettings(QString settingPath, QObject *parent) + : SettingsManager(settingPath+"messages.ini",parent) +{ +} + +QString MessageSettings::getMessageAt(int index) +{ + return getValue(QString("msg%1").arg(index),"messages").toString(); +} + +int MessageSettings::getCount() +{ + return getValue("count", "messages").toInt(); +} + +void MessageSettings::setCount(int count) +{ + setValue(count,"count","messages"); +} + +void MessageSettings::setMessageAt(int index, QString message) +{ + setValue(message,QString("msg%1").arg(index),"messages"); +} diff --git a/cockatrice/src/settings/messagesettings.h b/cockatrice/src/settings/messagesettings.h new file mode 100644 index 00000000..4ac4592e --- /dev/null +++ b/cockatrice/src/settings/messagesettings.h @@ -0,0 +1,29 @@ +#ifndef MESSAGESETTINGS_H +#define MESSAGESETTINGS_H + +#include "settingsmanager.h" + +class MessageSettings : public SettingsManager +{ + Q_OBJECT + friend class SettingsCache; + +public: + int getCount(); + QString getMessageAt(int index); + + void setCount(int count); + void setMessageAt(int index, QString message); +signals: + +public slots: + +private: + MessageSettings(QString settingPath, QObject *parent = 0); + MessageSettings( const MessageSettings& /*other*/ ); + MessageSettings( MessageSettings& /*other*/ ); + MessageSettings( volatile const MessageSettings& /*other*/ ); + MessageSettings( volatile MessageSettings& /*other*/ ); +}; + +#endif // MESSAGESETTINGS_H diff --git a/cockatrice/src/settings/serverssettings.cpp b/cockatrice/src/settings/serverssettings.cpp new file mode 100644 index 00000000..e698e127 --- /dev/null +++ b/cockatrice/src/settings/serverssettings.cpp @@ -0,0 +1,102 @@ +#include "serverssettings.h" + +ServersSettings::ServersSettings(QString settingPath, QObject *parent) + : SettingsManager(settingPath+"servers.ini", parent) +{ +} + +void ServersSettings::setPreviousHostLogin(int previous) +{ + setValue(previous, "previoushostlogin", "server"); +} + +int ServersSettings::getPreviousHostLogin() +{ + QVariant previous = getValue("previoushostlogin", "server"); + return previous == QVariant() ? 1 : previous.toInt(); +} + +void ServersSettings::setPreviousHostList(QStringList list) +{ + setValue(list, "previoushosts", "server"); +} + +QStringList ServersSettings::getPreviousHostList() +{ + return getValue("previoushosts", "server").toStringList(); +} + +void ServersSettings::setPrevioushostindex(int index) +{ + setValue(index, "previoushostindex", "server"); +} + +int ServersSettings::getPrevioushostindex() +{ + return getValue("previoushostindex", "server").toInt(); +} + +void ServersSettings::setHostName(QString hostname) +{ + setValue(hostname, "hostname", "server"); +} + +QString ServersSettings::getHostname(QString defaultHost) +{ + QVariant hostname = getValue("hostname","server"); + return hostname == QVariant() ? defaultHost : hostname.toString(); +} + +void ServersSettings::setPort(QString port) +{ + setValue(port, "port", "server"); +} + +QString ServersSettings::getPort(QString defaultPort) +{ + QVariant port = getValue("port","server"); + return port == QVariant() ? defaultPort : port.toString(); +} + +void ServersSettings::setPlayerName(QString playerName) +{ + setValue(playerName, "playername", "server"); +} + +QString ServersSettings::getPlayerName(QString defaultName) +{ + QVariant name = getValue("playername", "server"); + return name == QVariant() ? defaultName : name.toString(); +} + +void ServersSettings::setPassword(QString password) +{ + setValue(password, "password", "server"); +} + +QString ServersSettings::getPassword() +{ + return getValue("password", "server").toString(); +} + +void ServersSettings::setSavePassword(int save) +{ + setValue(save, "save_password", "server"); +} + +int ServersSettings::getSavePassword() +{ + QVariant save = getValue("save_password", "server"); + return save == QVariant() ? 1 : save.toInt(); +} + +void ServersSettings::setAutoConnect(int autoconnect) +{ + setValue(autoconnect, "auto_connect", "server"); +} + +int ServersSettings::getAutoConnect() +{ + QVariant autoconnect = getValue("auto_connect", "server"); + return autoconnect == QVariant() ? 0 : autoconnect.toInt(); +} diff --git a/cockatrice/src/settings/serverssettings.h b/cockatrice/src/settings/serverssettings.h new file mode 100644 index 00000000..9d3fad8c --- /dev/null +++ b/cockatrice/src/settings/serverssettings.h @@ -0,0 +1,44 @@ +#ifndef SERVERSSETTINGS_H +#define SERVERSSETTINGS_H + +#include "settingsmanager.h" +#include + +class ServersSettings : public SettingsManager +{ + Q_OBJECT + friend class SettingsCache; + +public: + int getPreviousHostLogin(); + QStringList getPreviousHostList(); + int getPrevioushostindex(); + QString getHostname(QString defaultHost = ""); + QString getPort(QString defaultPort = ""); + QString getPlayerName(QString defaultName = ""); + QString getPassword(); + int getSavePassword(); + int getAutoConnect(); + + void setPreviousHostLogin(int previous); + void setPreviousHostList(QStringList list); + void setPrevioushostindex(int index); + void setHostName(QString hostname); + void setPort(QString port); + void setPlayerName(QString playerName); + void setPassword(QString password); + void setSavePassword(int save); + void setAutoConnect(int autoconnect); +signals: + +public slots: + +private: + ServersSettings(QString settingPath,QObject *parent = 0); + ServersSettings( const ServersSettings& /*other*/ ); + ServersSettings( ServersSettings& /*other*/ ); + ServersSettings( volatile const ServersSettings& /*other*/ ); + ServersSettings( volatile ServersSettings& /*other*/ ); +}; + +#endif // SERVERSSETTINGS_H diff --git a/cockatrice/src/settings/settingsmanager.cpp b/cockatrice/src/settings/settingsmanager.cpp new file mode 100644 index 00000000..0735fd41 --- /dev/null +++ b/cockatrice/src/settings/settingsmanager.cpp @@ -0,0 +1,43 @@ +#include "settingsmanager.h" + +SettingsManager::SettingsManager(QString settingPath, QObject *parent) + : QObject(parent), + settings(settingPath, QSettings::IniFormat) +{ +} + +void SettingsManager::setValue(QVariant value, QString name, QString group, QString subGroup) +{ + if(!group.isEmpty()) + settings.beginGroup(group); + + if(!subGroup.isEmpty()) + settings.beginGroup(subGroup); + + settings.setValue(name, value); + + if(!subGroup.isEmpty()) + settings.endGroup(); + + if(!group.isEmpty()) + settings.endGroup(); +} + +QVariant SettingsManager::getValue(QString name, QString group, QString subGroup) +{ + if(!group.isEmpty()) + settings.beginGroup(group); + + if(!subGroup.isEmpty()) + settings.beginGroup(subGroup); + + QVariant value = settings.value(name); + + if(!subGroup.isEmpty()) + settings.endGroup(); + + if(!group.isEmpty()) + settings.endGroup(); + + return value; +} diff --git a/cockatrice/src/settings/settingsmanager.h b/cockatrice/src/settings/settingsmanager.h new file mode 100644 index 00000000..1ff6bf65 --- /dev/null +++ b/cockatrice/src/settings/settingsmanager.h @@ -0,0 +1,25 @@ +#ifndef SETTINGSMANAGER_H +#define SETTINGSMANAGER_H + +#include +#include +#include +#include + +class SettingsManager : public QObject +{ + Q_OBJECT +public: + SettingsManager(QString settingPath, QObject *parent = 0); + +signals: + +public slots: + +protected: + QSettings settings; + QVariant getValue(QString name, QString group = "", QString subGroup = "" ); + void setValue(QVariant value, QString name, QString group = "", QString subGroup = "" ); +}; + +#endif // SETTINGSMANAGER_H diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 9a3fb54d..3a1b7b5c 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -1,5 +1,7 @@ #include "settingscache.h" #include +#include + #if QT_VERSION >= 0x050000 #include #else @@ -8,28 +10,129 @@ QString SettingsCache::getSettingsPath() { - QString file = ""; + QString file = "settings/"; #ifndef PORTABLE_BUILD -#if QT_VERSION >= 0x050000 + #if QT_VERSION >= 0x050000 file = QStandardPaths::writableLocation(QStandardPaths::DataLocation); #else file = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #endif file.append("/settings/"); -#endif +#endif return file; } +void SettingsCache::translateLegacySettings() +{ + //NOTE Please remove this legacy setting translation after 2016-9-1 (+1 year after creation) + + //Layouts + QFile layoutFile(getSettingsPath()+"layouts/deckLayout.ini"); + if(layoutFile.exists()) + if(layoutFile.copy(getSettingsPath()+"layouts.ini")) + layoutFile.remove(); + + QStringList usedKeys; + QSettings legacySetting; + + //Sets + legacySetting.beginGroup("sets"); + QStringList setsGroups = legacySetting.childGroups(); + for(int i = 0; i < setsGroups.size(); i++){ + legacySetting.beginGroup(setsGroups.at(i)); + cardDatabase().setEnabled(setsGroups.at(i), legacySetting.value("enabled").toBool()); + cardDatabase().setIsKnown(setsGroups.at(i), legacySetting.value("isknown").toBool()); + cardDatabase().setSortKey(setsGroups.at(i), legacySetting.value("sortkey").toUInt()); + legacySetting.endGroup(); + } + QStringList setsKeys = legacySetting.allKeys(); + for (int i = 0; i < setsKeys.size(); ++i) { + usedKeys.append("sets/"+setsKeys.at(i)); + } + legacySetting.endGroup(); + + //Servers + legacySetting.beginGroup("server"); + servers().setPreviousHostLogin(legacySetting.value("previoushostlogin").toInt()); + servers().setPreviousHostList(legacySetting.value("previoushosts").toStringList()); + servers().setPrevioushostindex(legacySetting.value("previoushostindex").toInt()); + servers().setHostName(legacySetting.value("hostname").toString()); + servers().setPort(legacySetting.value("port").toString()); + servers().setPlayerName(legacySetting.value("playername").toString()); + servers().setPassword(legacySetting.value("password").toString()); + servers().setSavePassword(legacySetting.value("save_password").toInt()); + servers().setAutoConnect(legacySetting.value("auto_connect").toInt()); + usedKeys.append(legacySetting.allKeys()); + QStringList allKeysServer = legacySetting.allKeys(); + for (int i = 0; i < allKeysServer.size(); ++i) { + usedKeys.append("server/"+allKeysServer.at(i)); + } + legacySetting.endGroup(); + + //Messages + legacySetting.beginGroup("messages"); + QStringList allMessages = legacySetting.allKeys(); + for (int i = 0; i < allMessages.size(); ++i) { + if(allMessages.at(i) != "count"){ + QString temp = allMessages.at(i); + int index = temp.remove("msg").toInt(); + messages().setMessageAt(index,legacySetting.value(allMessages.at(i)).toString()); + } + } + messages().setCount(legacySetting.value("count").toInt()); + QStringList allKeysmessages = legacySetting.allKeys(); + for (int i = 0; i < allKeysmessages.size(); ++i) { + usedKeys.append("messages/"+allKeysmessages.at(i)); + } + legacySetting.endGroup(); + + //Game filters + legacySetting.beginGroup("filter_games"); + gameFilters().setUnavailableGamesVisible(legacySetting.value("unavailable_games_visible").toBool()); + gameFilters().setShowPasswordProtectedGames(legacySetting.value("show_password_protected_games").toBool()); + gameFilters().setGameNameFilter(legacySetting.value("game_name_filter").toString()); + gameFilters().setMinPlayers(legacySetting.value("min_players").toInt()); + gameFilters().setMaxPlayers(legacySetting.value("max_players").toInt()); + + QStringList allFilters = legacySetting.allKeys(); + for (int i = 0; i < allFilters.size(); ++i) { + if(allFilters.at(i).startsWith("game_type")){ + gameFilters().setGameHashedTypeEnabled(allFilters.at(i), legacySetting.value(allFilters.at(i)).toBool()); + } + } + QStringList allKeysfilter_games = legacySetting.allKeys(); + for (int i = 0; i < allKeysfilter_games.size(); ++i) { + usedKeys.append("filter_games/"+allKeysfilter_games.at(i)); + } + legacySetting.endGroup(); + + QStringList allLegacyKeys = legacySetting.allKeys(); + for (int i = 0; i < allLegacyKeys.size(); ++i) { + if(usedKeys.contains(allLegacyKeys.at(i))) + continue; + settings->setValue(allLegacyKeys.at(i), legacySetting.value(allLegacyKeys.at(i))); + } +} + SettingsCache::SettingsCache() { - settings = new QSettings(this); - shortcutsSettings = new ShortcutsSettings(getSettingsPath(),this); + QString settingsPath = getSettingsPath(); + settings = new QSettings(settingsPath+"global.ini", QSettings::IniFormat, this); + shortcutsSettings = new ShortcutsSettings(settingsPath,this); + cardDatabaseSettings = new CardDatabaseSettings(settingsPath,this); + serversSettings = new ServersSettings(settingsPath,this); + messageSettings = new MessageSettings(settingsPath,this); + gameFiltersSettings = new GameFiltersSettings(settingsPath, this); + layoutsSettings = new LayoutsSettings(settingsPath, this); + if(!QFile(settingsPath+"global.ini").exists()) + translateLegacySettings(); + + notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool(); lang = settings->value("personal/lang").toString(); keepalive = settings->value("personal/keepalive", 5).toInt(); - deckPath = settings->value("paths/decks").toString(); replaysPath = settings->value("paths/replays").toString(); picsPath = settings->value("paths/pics").toString(); @@ -116,17 +219,6 @@ SettingsCache::SettingsCache() spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool(); rememberGameSettings = settings->value("game/remembergamesettings", true).toBool(); clientID = settings->value("personal/clientid", "notset").toString(); - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - - QSettings layout_settings(file , QSettings::IniFormat); - deckEditorLayoutState = layout_settings.value("layouts/deckEditor_state").toByteArray(); - deckEditorGeometry = layout_settings.value("layouts/deckEditor_geometry").toByteArray(); - - deckEditorCardSize = layout_settings.value("layouts/deckEditor_CardSize", QSize(250,500)).toSize(); - deckEditorFilterSize = layout_settings.value("layouts/deckEditor_FilterSize", QSize(250,250)).toSize(); - deckEditorDeckSize = layout_settings.value("layouts/deckEditor_DeckSize", QSize(250,360)).toSize(); } void SettingsCache::setCardInfoViewMode(const int _viewMode) { @@ -471,56 +563,6 @@ QStringList SettingsCache::getCountries() const return countries; } -void SettingsCache::setDeckEditorLayoutState(const QByteArray &value) -{ - deckEditorLayoutState = value; - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - QSettings layout_settings(file , QSettings::IniFormat); - layout_settings.setValue("layouts/deckEditor_state",value); -} - -void SettingsCache::setDeckEditorGeometry(const QByteArray &value) -{ - deckEditorGeometry = value; - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - QSettings layout_settings(file , QSettings::IniFormat); - layout_settings.setValue("layouts/deckEditor_geometry",value); -} - -void SettingsCache::setDeckEditorCardSize(const QSize &value) -{ - deckEditorCardSize = value; - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - QSettings layout_settings(file , QSettings::IniFormat); - layout_settings.setValue("layouts/deckEditor_CardSize",value); -} - -void SettingsCache::setDeckEditorDeckSize(const QSize &value) -{ - deckEditorDeckSize = value; - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - QSettings layout_settings(file , QSettings::IniFormat); - layout_settings.setValue("layouts/deckEditor_DeckSize",value); -} - -void SettingsCache::setDeckEditorFilterSize(const QSize &value) -{ - deckEditorFilterSize = value; - - QString file = getSettingsPath(); - file.append("layouts/deckLayout.ini"); - QSettings layout_settings(file , QSettings::IniFormat); - layout_settings.setValue("layouts/deckEditor_FilterSize",value); -} - void SettingsCache::setGameDescription(const QString _gameDescription) { gameDescription = _gameDescription; @@ -579,4 +621,10 @@ void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings) { rememberGameSettings = _rememberGameSettings; settings->setValue("game/remembergamesettings", rememberGameSettings); +} + +void SettingsCache::setNotifyAboutUpdate(int _notifyaboutupdate) +{ + notifyAboutUpdates = _notifyaboutupdate; + settings->setValue("personal/updatenotification", notifyAboutUpdates); } \ No newline at end of file diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 6e439ca1..1cfe4d42 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -5,6 +5,11 @@ #include #include #include "shortcutssettings.h" +#include "settings/carddatabasesettings.h" +#include "settings/serverssettings.h" +#include "settings/messagesettings.h" +#include "settings/gamefilterssettings.h" +#include "settings/layoutssettings.h" // the falbacks are used for cards without a muid #define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card" @@ -44,9 +49,16 @@ signals: private: QSettings *settings; ShortcutsSettings *shortcutsSettings; + CardDatabaseSettings *cardDatabaseSettings; + ServersSettings *serversSettings; + MessageSettings *messageSettings; + GameFiltersSettings *gameFiltersSettings; + LayoutsSettings *layoutsSettings; + QByteArray mainWindowGeometry; QString lang; QString deckPath, replaysPath, picsPath, cardDatabasePath, tokenDatabasePath, themeName; + bool notifyAboutUpdates; bool picDownload; bool picDownloadHq; bool notificationsEnabled; @@ -97,14 +109,13 @@ private: bool spectatorsNeedPassword; bool spectatorsCanTalk; bool spectatorsCanSeeEverything; + int keepalive; + void translateLegacySettings(); bool rememberGameSettings; - int keepalive; - QByteArray deckEditorLayoutState, deckEditorGeometry; - QSize deckEditorFilterSize, deckEditorDeckSize, deckEditorCardSize; - QString getSettingsPath(); public: SettingsCache(); + QString getSettingsPath(); const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; } QString getLang() const { return lang; } QString getDeckPath() const { return deckPath; } @@ -119,6 +130,7 @@ public: bool getPicDownloadHq() const { return picDownloadHq; } bool getNotificationsEnabled() const { return notificationsEnabled; } bool getSpectatorNotificationsEnabled() const { return spectatorNotificationsEnabled; } + bool getNotifyAboutUpdates() const { return notifyAboutUpdates; } bool getDoubleClickToPlay() const { return doubleClickToPlay; } bool getPlayToStack() const { return playToStack; } @@ -173,19 +185,13 @@ public: bool getRememberGameSettings() const { return rememberGameSettings; } int getKeepAlive() const { return keepalive; } void setClientID(QString clientID); - QString getClientID() { return clientID; } - QByteArray getDeckEditorLayoutState() const { return deckEditorLayoutState; } - void setDeckEditorLayoutState(const QByteArray &value); - QByteArray getDeckEditorGeometry() const { return deckEditorGeometry; } - void setDeckEditorGeometry(const QByteArray &value); - QSize getDeckEditorCardSize() const { return deckEditorCardSize; } - void setDeckEditorCardSize(const QSize &value); - QSize getDeckEditorDeckSize() const { return deckEditorDeckSize; } - void setDeckEditorDeckSize(const QSize &value); - QSize getDeckEditorFilterSize() const { return deckEditorFilterSize; } - void setDeckEditorFilterSize(const QSize &value); + QString getClientID() { return clientID; } ShortcutsSettings& shortcuts() const { return *shortcutsSettings; } - + CardDatabaseSettings& cardDatabase() const { return *cardDatabaseSettings; } + ServersSettings& servers() const { return *serversSettings; } + MessageSettings& messages() const { return *messageSettings; } + GameFiltersSettings& gameFilters() const { return *gameFiltersSettings; } + LayoutsSettings& layouts() const { return *layoutsSettings; } public slots: void setMainWindowGeometry(const QByteArray &_mainWindowGeometry); void setLang(const QString &_lang); @@ -247,6 +253,7 @@ public slots: void setSpectatorsCanTalk(const bool _spectatorsCanTalk); void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything); void setRememberGameSettings(const bool _rememberGameSettings); + void setNotifyAboutUpdate(int _notifyaboutupdate); }; extern SettingsCache *settingsCache; diff --git a/cockatrice/src/tab_deck_editor.cpp b/cockatrice/src/tab_deck_editor.cpp index 0bef8e7a..9552638a 100644 --- a/cockatrice/src/tab_deck_editor.cpp +++ b/cockatrice/src/tab_deck_editor.cpp @@ -494,21 +494,21 @@ void TabDeckEditor::refreshShortcuts() void TabDeckEditor::loadLayout() { - MainWindow->restoreState(settingsCache->getDeckEditorLayoutState()); - MainWindow->restoreGeometry(settingsCache->getDeckEditorGeometry()); + MainWindow->restoreState(settingsCache->layouts().getDeckEditorLayoutState()); + MainWindow->restoreGeometry(settingsCache->layouts().getDeckEditorGeometry()); btnCard->setChecked(!cardInfoDock->isHidden()); btnFilter->setChecked(!filterDock->isHidden()); btnDeck->setChecked(!deckDock->isHidden()); - cardInfoDock->setMinimumSize(settingsCache->getDeckEditorCardSize()); - cardInfoDock->setMaximumSize(settingsCache->getDeckEditorCardSize()); + cardInfoDock->setMinimumSize(settingsCache->layouts().getDeckEditorCardSize()); + cardInfoDock->setMaximumSize(settingsCache->layouts().getDeckEditorCardSize()); - filterDock->setMinimumSize(settingsCache->getDeckEditorFilterSize()); - filterDock->setMaximumSize(settingsCache->getDeckEditorFilterSize()); + filterDock->setMinimumSize(settingsCache->layouts().getDeckEditorFilterSize()); + filterDock->setMaximumSize(settingsCache->layouts().getDeckEditorFilterSize()); - deckDock->setMinimumSize(settingsCache->getDeckEditorDeckSize()); - deckDock->setMaximumSize(settingsCache->getDeckEditorDeckSize()); + deckDock->setMinimumSize(settingsCache->layouts().getDeckEditorDeckSize()); + deckDock->setMaximumSize(settingsCache->layouts().getDeckEditorDeckSize()); QTimer::singleShot(100, this, SLOT(freeDocksSize())); } @@ -1009,11 +1009,11 @@ bool TabDeckEditor::eventFilter(QObject * o, QEvent * e) btnFilter->setChecked(false); } if( o == this && e->type() == QEvent::Hide){ - settingsCache->setDeckEditorLayoutState(MainWindow->saveState()); - settingsCache->setDeckEditorGeometry(MainWindow->saveGeometry()); - settingsCache->setDeckEditorCardSize(cardInfoDock->size()); - settingsCache->setDeckEditorFilterSize(filterDock->size()); - settingsCache->setDeckEditorDeckSize(deckDock->size()); + settingsCache->layouts().setDeckEditorLayoutState(MainWindow->saveState()); + settingsCache->layouts().setDeckEditorGeometry(MainWindow->saveGeometry()); + settingsCache->layouts().setDeckEditorCardSize(cardInfoDock->size()); + settingsCache->layouts().setDeckEditorFilterSize(filterDock->size()); + settingsCache->layouts().setDeckEditorDeckSize(deckDock->size()); } return false; } diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index 812fc1df..6ff7a56e 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -30,6 +30,7 @@ #include #include #include + #if QT_VERSION < 0x050000 #include // for Qt::escape() #endif @@ -293,9 +294,23 @@ void MainWindow::serverTimeout() actConnect(); } -void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime) +void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime, QList missingFeatures) { switch (r) { + case Response::RespClientUpdateRequired: { + QString formatedMissingFeatures; + formatedMissingFeatures = "Missing Features: "; + for (int i = 0; i < missingFeatures.size(); ++i) + formatedMissingFeatures.append(QString("\n %1").arg(QChar(0x2022)) + " " + missingFeatures.value(i) ); + + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Critical); + msgBox.setWindowTitle(tr("Failed Login")); + msgBox.setText(tr("Your client does not support features that the server requires, please update your client and try again.")); + msgBox.setDetailedText(formatedMissingFeatures); + msgBox.exec(); + break; + } case Response::RespWrongPassword: QMessageBox::critical(this, tr("Error"), tr("Incorrect username or password. Please check your authentication information and try again.")); break; @@ -561,13 +576,13 @@ MainWindow::MainWindow(QWidget *parent) client = new RemoteClient; connect(client, SIGNAL(connectionClosedEventReceived(const Event_ConnectionClosed &)), this, SLOT(processConnectionClosedEvent(const Event_ConnectionClosed &))); connect(client, SIGNAL(serverShutdownEventReceived(const Event_ServerShutdown &)), this, SLOT(processServerShutdownEvent(const Event_ServerShutdown &))); - connect(client, SIGNAL(loginError(Response::ResponseCode, QString, quint32)), this, SLOT(loginError(Response::ResponseCode, QString, quint32))); + connect(client, SIGNAL(loginError(Response::ResponseCode, QString, quint32, QList)), this, SLOT(loginError(Response::ResponseCode, QString, quint32, QList))); connect(client, SIGNAL(socketError(const QString &)), this, SLOT(socketError(const QString &))); connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())); connect(client, SIGNAL(statusChanged(ClientStatus)), this, SLOT(statusChanged(ClientStatus))); connect(client, SIGNAL(protocolVersionMismatch(int, int)), this, SLOT(protocolVersionMismatch(int, int))); connect(client, SIGNAL(userInfoChanged(const ServerInfo_User &)), this, SLOT(userInfoReceived(const ServerInfo_User &)), Qt::BlockingQueuedConnection); - + connect(client, SIGNAL(notifyUserAboutUpdate()), this, SLOT(notifyUserAboutUpdate())); connect(client, SIGNAL(registerAccepted()), this, SLOT(registerAccepted())); connect(client, SIGNAL(registerAcceptedNeedsActivate()), this, SLOT(registerAcceptedNeedsActivate())); connect(client, SIGNAL(registerError(Response::ResponseCode, QString, quint32)), this, SLOT(registerError(Response::ResponseCode, QString, quint32))); @@ -795,3 +810,8 @@ void MainWindow::refreshShortcuts() aExit->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aExit")); aCheckCardUpdates->setShortcuts(settingsCache->shortcuts().getShortcut("MainWindow/aCheckCardUpdates")); } + +void MainWindow::notifyUserAboutUpdate() +{ + QMessageBox::information(this, tr("Information"), tr("Your client appears to be missing features that the server supports.\nThis usually means that your client version is out of date,pleae check to see if there is a new client available for download.")); +} diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 5a12676e..149f7197 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -20,6 +20,7 @@ #ifndef WINDOW_H #define WINDOW_H +#include #include #include #include @@ -42,7 +43,7 @@ private slots: void processConnectionClosedEvent(const Event_ConnectionClosed &event); void processServerShutdownEvent(const Event_ServerShutdown &event); void serverTimeout(); - void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime); + void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime, QList missingFeatures); void registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime); void activateError(); void socketError(const QString &errorStr); @@ -53,7 +54,7 @@ private slots: void activateAccepted(); void localGameEnded(); void pixmapCacheSizeChanged(int newSizeInMBs); - + void notifyUserAboutUpdate(); void actConnect(); void actDisconnect(); void actSinglePlayer(); diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 47dab1f5..d73dc6f8 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -7,6 +7,7 @@ add_subdirectory(pb) SET(common_SOURCES decklist.cpp + featureset.cpp get_pb_extension.cpp rng_abstract.cpp rng_sfmt.cpp diff --git a/common/featureset.cpp b/common/featureset.cpp new file mode 100644 index 00000000..f940a461 --- /dev/null +++ b/common/featureset.cpp @@ -0,0 +1,55 @@ +#include "featureset.h" +#include +#include + +FeatureSet::FeatureSet() +{ + +} + +QMap FeatureSet::getDefaultFeatureList() { + initalizeFeatureList(featureList); + return featureList; +} + +void FeatureSet::initalizeFeatureList(QMap &featureList){ + featureList.insert("client_id", false); + featureList.insert("client_ver", false); + featureList.insert("feature_set", false); +} + +void FeatureSet::enableRequiredFeature(QMap &featureList, QString featureName){ + if (featureList.contains(featureName)) + featureList.insert(featureName,true); +} + +void FeatureSet::disableRequiredFeature(QMap &featureList, QString featureName){ + if (featureList.contains(featureName)) + featureList.insert(featureName,false); +} + +QMap FeatureSet::addFeature(QMap &featureList, QString featureName, bool isFeatureRequired){ + featureList.insert(featureName,isFeatureRequired); + return featureList; +} + +QMap FeatureSet::identifyMissingFeatures(QMap suppliedFeatures, QMap requiredFeatures){ + QMap missingList; + QMap::iterator i; + for (i = requiredFeatures.begin(); i != requiredFeatures.end(); ++i) { + if (!suppliedFeatures.contains(i.key())) { + missingList.insert(i.key(), i.value()); + } + } + return missingList; +} + +bool FeatureSet::isRequiredFeaturesMissing(QMap suppliedFeatures, QMap requiredFeatures) { + QMap::iterator i; + for (i = requiredFeatures.begin(); i != requiredFeatures.end(); ++i) { + if (i.value() && suppliedFeatures.contains(i.key())) { + return true; + } + } + return false; +} diff --git a/common/featureset.h b/common/featureset.h new file mode 100644 index 00000000..620ba96a --- /dev/null +++ b/common/featureset.h @@ -0,0 +1,24 @@ +#ifndef FEATURESET_H +#define FEATURESET_H + +#include +#include +#include + +class FeatureSet +{ +public: + FeatureSet(); + QMap getDefaultFeatureList(); + void initalizeFeatureList(QMap &featureList); + void enableRequiredFeature(QMap &featureList, QString featureName); + void disableRequiredFeature(QMap &featureList, QString featureName); + QMap addFeature(QMap &featureList, QString featureName, bool isFeatureRequired); + QMap identifyMissingFeatures(QMap featureListToCheck, QMap featureListToCompareTo); + bool isRequiredFeaturesMissing(QMap featureListToCheck, QMap featureListToCompareTo); +private: + QMap featureList; +}; + + +#endif // FEEATURESET_H diff --git a/common/pb/response.proto b/common/pb/response.proto index ba3ccc6a..ce2aec00 100644 --- a/common/pb/response.proto +++ b/common/pb/response.proto @@ -37,6 +37,7 @@ message Response { RespActivationFailed = 32; // Server didn't accept a reg user activation token RespRegistrationAcceptedNeedsActivation = 33; // Server accepted cient registration, but it will need token activation RespClientIdRequired = 34; // Server requires client to generate and send its client id before allowing access + RespClientUpdateRequired = 35; // Client is missing features that the server is requiring } enum ResponseType { JOIN_ROOM = 1000; diff --git a/common/pb/response_login.proto b/common/pb/response_login.proto index fecd9d83..673eaa46 100644 --- a/common/pb/response_login.proto +++ b/common/pb/response_login.proto @@ -11,4 +11,5 @@ message Response_Login { repeated ServerInfo_User ignore_list = 3; optional string denied_reason_str = 4; optional uint64 denied_end_time = 5; + repeated string missing_features = 6; } diff --git a/common/pb/session_commands.proto b/common/pb/session_commands.proto index 0d5b12bd..afd85a39 100644 --- a/common/pb/session_commands.proto +++ b/common/pb/session_commands.proto @@ -46,6 +46,7 @@ message Command_Login { optional string password = 2; optional string clientid = 3; optional string clientver = 4; + repeated string clientfeatures = 5; } message Command_Message { diff --git a/common/server.cpp b/common/server.cpp index 88d52909..e0a015ec 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -32,6 +32,7 @@ #include "pb/session_event.pb.h" #include "pb/event_connection_closed.pb.h" #include "pb/isl_message.pb.h" +#include "featureset.h" #include #include #include diff --git a/common/server.h b/common/server.h index 494ec534..e4b635e0 100644 --- a/common/server.h +++ b/common/server.h @@ -51,10 +51,10 @@ public: Server_AbstractUserInterface *findUser(const QString &userName) const; const QMap &getUsers() const { return users; } const QMap &getUsersBySessionId() const { return usersBySessionId; } + virtual QMap getServerRequiredFeatureList() const { return QMap(); } void addClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player); virtual QString getLoginMessage() const { return QString(); } - virtual bool permitUnregisteredUsers() const { return true; } virtual bool getGameShouldPing() const { return false; } virtual bool getClientIdRequired() const { return false; } @@ -94,6 +94,7 @@ private: mutable QReadWriteLock persistentPlayersLock; int nextLocalGameId; QMutex nextLocalGameIdMutex; + protected slots: void externalUserJoined(const ServerInfo_User &userInfo); void externalUserLeft(const QString &userName); diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 224ae2c7..f6ab7945 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -2,8 +2,6 @@ #define SERVER_DATABASE_INTERFACE_H #include -#include - #include "server.h" class Server_DatabaseInterface : public QObject { diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index c4ed0f51..775b204f 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -19,6 +19,8 @@ #include "pb/event_game_joined.pb.h" #include "pb/event_room_say.pb.h" #include +#include "featureset.h" + Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent) : QObject(parent), @@ -382,10 +384,32 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd { QString userName = QString::fromStdString(cmd.user_name()).simplified(); QString clientId = QString::fromStdString(cmd.clientid()).simplified(); - + if (userName.isEmpty() || (userInfo != 0)) return Response::RespContextError; + // check client feature set against server feature set + FeatureSet features; + QMap receivedClientFeatures; + QMap missingClientFeatures; + + for (int i = 0; i < cmd.clientfeatures().size(); ++i) + receivedClientFeatures.insert(QString::fromStdString(cmd.clientfeatures(i)).simplified(), false); + + missingClientFeatures = features.identifyMissingFeatures(receivedClientFeatures, server->getServerRequiredFeatureList()); + + if (!missingClientFeatures.isEmpty()) { + if (features.isRequiredFeaturesMissing(missingClientFeatures, server->getServerRequiredFeatureList())) { + Response_Login *re = new Response_Login; + re->set_denied_reason_str("Client upgrade required"); + QMap::iterator i; + for (i = missingClientFeatures.begin(); i != missingClientFeatures.end(); ++i) + re->add_missing_features(i.key().toStdString().c_str()); + rc.setResponseExtension(re); + return Response::RespClientUpdateRequired; + } + } + QString reasonStr; int banSecondsLeft = 0; AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft, clientId); @@ -430,6 +454,13 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd re->add_ignore_list()->CopyFrom(ignoreIterator.next().value()); } + // return to client any missing features the server has that the client does not + if (!missingClientFeatures.isEmpty()) { + QMap::iterator i; + for (i = missingClientFeatures.begin(); i != missingClientFeatures.end(); ++i) + re->add_missing_features(i.key().toStdString().c_str()); + } + joinPersistentGames(rc); rc.setResponseExtension(re); diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index bf9d1940..5c9aef9a 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -8,11 +8,13 @@ #include "pb/response.pb.h" #include "pb/server_message.pb.h" +class Features; class Server_DatabaseInterface; class Server_Player; class ServerInfo_User; class Server_Room; class QTimer; +class FeatureSet; class ServerMessage; class Response; diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 08fdfabb..05c8a2e4 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -14,6 +14,12 @@ SET(oracle_SOURCES ../cockatrice/src/carddatabase.cpp ../cockatrice/src/settingscache.cpp ../cockatrice/src/shortcutssettings.cpp + ../cockatrice/src/settings/carddatabasesettings.cpp + ../cockatrice/src/settings/serverssettings.cpp + ../cockatrice/src/settings/settingsmanager.cpp + ../cockatrice/src/settings/messagesettings.cpp + ../cockatrice/src/settings/gamefilterssettings.cpp + ../cockatrice/src/settings/layoutssettings.cpp ../cockatrice/src/thememanager.cpp ../cockatrice/src/qt-json/json.cpp ) @@ -233,3 +239,8 @@ Translations = Resources/translations\") fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/oracle.exe\" \"\${QTPLUGINS}\" \"${libSearchDirs}\") " COMPONENT Runtime) endif() +#Compile a portable version, default off +option(PORTABLE "portable build" OFF) +IF(PORTABLE) +add_definitions(-DPORTABLE_BUILD) +endif() diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index 8351129c..32bfe6f7 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -45,16 +45,22 @@ OracleWizard::OracleWizard(QWidget *parent) : QWizard(parent) { - settings = new QSettings(this); + settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat, this); connect(settingsCache, SIGNAL(langChanged()), this, SLOT(updateLanguage())); - importer = new OracleImporter( -#if QT_VERSION < 0x050000 - QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QString dataDir; + +#ifndef PORTABLE_BUILD + #if QT_VERSION < 0x050000 + QDesktopServices::storageLocation(QDesktopServices::DataLocation); + #else + QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); + #endif #else - QStandardPaths::standardLocations(QStandardPaths::DataLocation).first() + dataDir.append("data"); #endif - , this); + + importer = new OracleImporter(dataDir, this); addPage(new IntroPage); addPage(new LoadSetsPage); @@ -484,6 +490,9 @@ void SaveSetsPage::retranslateUi() "Press \"Save\" to save the imported cards to the Cockatrice database.")); defaultPathCheckBox->setText(tr("Save to the default path (recommended)")); + #ifdef PORTABLE_BUILD + defaultPathCheckBox->setEnabled(false); + #endif } void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, const QString &setName) @@ -499,14 +508,25 @@ void SaveSetsPage::updateTotalProgress(int cardsImported, int /* setIndex */, co bool SaveSetsPage::validatePage() { bool ok = false; - const QString dataDir = + QString dataDir; + #ifndef PORTABLE_BUILD #if QT_VERSION < 0x050000 - QDesktopServices::storageLocation(QDesktopServices::DataLocation); + dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #else - QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); + dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); #endif - QSettings* settings = new QSettings(this); +#else + dataDir = "data"; +#endif + +#ifdef PORTABLE_BUILD + QSettings* settings = new QSettings("settings/global.ini",QSettings::IniFormat,this); + QString defaultPath = "data/cards.xml"; + settings->setValue("paths/carddatabase", defaultPath); +#else + QSettings* settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat,this); QString defaultPath = settings->value("paths/carddatabase").toString(); +#endif QString windowName = tr("Save card database"); QString fileType = tr("XML; card database (*.xml)"); @@ -517,6 +537,7 @@ bool SaveSetsPage::validatePage() fileName = dataDir + "/cards.xml"; else fileName = QFileDialog::getSaveFileName(this, windowName, dataDir + "/cards.xml", fileType); + settings->setValue("paths/carddatabase", fileName); } else { @@ -694,19 +715,34 @@ void SaveTokensPage::retranslateUi() "Press \"Save\" to save the imported tokens to the Cockatrice tokens database.")); defaultPathCheckBox->setText(tr("Save to the default path (recommended)")); + #ifdef PORTABLE_BUILD + defaultPathCheckBox->setEnabled(false); + #endif } bool SaveTokensPage::validatePage() { bool ok = false; - const QString dataDir = + QString dataDir; + #ifndef PORTABLE_BUILD #if QT_VERSION < 0x050000 - QDesktopServices::storageLocation(QDesktopServices::DataLocation); + dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation); #else - QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); + dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); #endif - QSettings* settings = new QSettings(this); +#else + dataDir = "data"; +#endif + +#ifdef PORTABLE_BUILD + QSettings* settings = new QSettings("settings/global.ini",QSettings::IniFormat,this); + QString defaultPath = "data/tokens.xml"; + settings->setValue("paths/tokendatabase", defaultPath); +#else + QSettings* settings = new QSettings(settingsCache->getSettingsPath()+"global.ini",QSettings::IniFormat,this); QString defaultPath = settings->value("paths/tokendatabase").toString(); +#endif + QString windowName = tr("Save token database"); QString fileType = tr("XML; token database (*.xml)"); diff --git a/servatrice/CMakeLists.txt b/servatrice/CMakeLists.txt index 6fa529ff..047a3f53 100644 --- a/servatrice/CMakeLists.txt +++ b/servatrice/CMakeLists.txt @@ -194,3 +194,8 @@ Translations = Resources/translations\") fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/servatrice.exe\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\") " COMPONENT Runtime) endif() +#Compile a portable version, default off +option(PORTABLE "portable build" OFF) +IF(PORTABLE) +add_definitions(-DPORTABLE_BUILD) +endif() diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index ce57df53..842fb032 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -50,6 +50,12 @@ max_player_inactivity_time=15 ' require that clients report the client ID in order to log into the server. Default is false requireclientid=false +; You can limit the types of clients that connect to the server by requiring different features be available +; on the client. This setting can contain a comma-seperated list of features. if any of the features +; listed in this line are not available on the client the client will be denied access to the server upon +; attempting to log in. Example: "client_id,client_ver" +requiredfeatures="" + [authentication] ; Servatrice can authenticate users connecting. It currently supports 3 different authentication methods: diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index 499b468d..d19ebb66 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -198,6 +198,7 @@ int main(int argc, char *argv[]) #else qInstallMessageHandler(myMessageOutput); #endif + retval = app.exec(); std::cerr << "Server quit." << std::endl; diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 701902f8..f1f29191 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -38,6 +38,7 @@ #include "pb/event_server_message.pb.h" #include "pb/event_server_shutdown.pb.h" #include "pb/event_connection_closed.pb.h" +#include "featureset.h" Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent) : QTcpServer(parent), @@ -179,6 +180,16 @@ bool Servatrice::initServer() if (registrationEnabled) qDebug() << "Require email address to register: " << requireEmailForRegistration; + FeatureSet features; + features.initalizeFeatureList(serverRequiredFeatureList); + requiredFeatures = settingsCache->value("server/requiredfeatures","").toString(); + QStringList listReqFeatures = requiredFeatures.split(",", QString::SkipEmptyParts); + if (!listReqFeatures.isEmpty()) + foreach(QString reqFeature, listReqFeatures) + features.enableRequiredFeature(serverRequiredFeatureList,reqFeature); + + qDebug() << "Required client features: " << serverRequiredFeatureList; + QString dbTypeStr = settingsCache->value("database/type").toString(); if (dbTypeStr == "mysql") databaseType = DatabaseMySql; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 4e4a74b2..ad42497b 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -30,6 +30,7 @@ #include #include "server.h" + Q_DECLARE_METATYPE(QSqlDatabase) class QSqlQuery; @@ -41,6 +42,7 @@ class Servatrice_ConnectionPool; class Servatrice_DatabaseInterface; class ServerSocketInterface; class IslInterface; +class FeatureSet; class Servatrice_GameServer : public QTcpServer { Q_OBJECT @@ -109,6 +111,8 @@ private: mutable QMutex loginMessageMutex; QString loginMessage; QString dbPrefix; + QString requiredFeatures; + QMap serverRequiredFeatureList; Servatrice_DatabaseInterface *servatriceDatabaseInterface; int serverId; int uptime; @@ -134,8 +138,10 @@ public: Servatrice(QObject *parent = 0); ~Servatrice(); bool initServer(); + QMap getServerRequiredFeatureList() const { return serverRequiredFeatureList; } QString getServerName() const { return serverName; } QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } + QString getRequiredFeatures() const { return requiredFeatures; } bool permitUnregisteredUsers() const { return authenticationMethod != AuthenticationNone; } bool getGameShouldPing() const { return true; } bool getClientIdRequired() const { return clientIdRequired; } diff --git a/servatrice/src/settingscache.cpp b/servatrice/src/settingscache.cpp index b2b74d74..1adad629 100644 --- a/servatrice/src/settingscache.cpp +++ b/servatrice/src/settingscache.cpp @@ -15,9 +15,11 @@ SettingsCache::SettingsCache(const QString & fileName, QSettings::Format format, QString SettingsCache::guessConfigurationPath(QString & specificPath) { - const QString fileName="servatrice.ini"; + const QString fileName="servatrice.ini"; + #ifdef PORTABLE_BUILD + return fileName; + #endif QString guessFileName; - // specific path if(!specificPath.isEmpty() && QFile::exists(specificPath)) return specificPath; @@ -40,4 +42,4 @@ QString SettingsCache::guessConfigurationPath(QString & specificPath) guessFileName = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/" + fileName; #endif return guessFileName; -} \ No newline at end of file +}