diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 75fbc59f1..e895e2220 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,7 +40,7 @@ jobs: steps: - name: "Checkout repository" - uses: actions/checkout@v7 + uses: actions/checkout@v6 - name: "Initialize CodeQL" uses: github/codeql-action/init@v4 diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index 255e8b045..df4fe233c 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -127,7 +127,7 @@ jobs: steps: - name: "Download digests" - uses: actions/download-artifact@v8 + uses: actions/download-artifact@v7 with: path: ${{ runner.temp }}/digests pattern: digest-* diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp b/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp index a4a31d78d..198fa259b 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp +++ b/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.cpp @@ -1,17 +1,9 @@ #include "dlg_convert_deck_to_cod_format.h" -#include "../../../client/settings/cache_settings.h" -#include "../../deck_loader/deck_loader.h" - #include #include -#include -#include -#include #include -#include #include -#include DialogConvertDeckToCodFormat::DialogConvertDeckToCodFormat(QWidget *parent) : QDialog(parent) { @@ -46,71 +38,3 @@ bool DialogConvertDeckToCodFormat::dontAskAgain() const { return dontAskAgainCheckbox->isChecked(); } - -namespace -{ - -bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath) -{ - QFileInfo fileInfo(filePath); - QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod"); - - if (QFile::exists(newFileName)) { - QMessageBox::StandardButton reply = - QMessageBox::question(parent, QObject::tr("Overwrite Existing File?"), - QObject::tr("A .cod version of this deck already exists. Overwrite it?"), - QMessageBox::Yes | QMessageBox::No); - return reply == QMessageBox::Yes; - } - return true; // Safe to proceed -} - -} // namespace - -bool DialogConvertDeckToCodFormat::promptIfRequired(QWidget *parent, - const QString &filePath, - const std::function &convert) -{ - if (DeckFileFormat::getFormatFromName(filePath) == DeckFileFormat::Cockatrice) { - return true; - } - - // Retrieve saved preference if the prompt is disabled - if (!SettingsCache::instance().visualDeckStorage().getVisualDeckStoragePromptForConversion()) { - if (!SettingsCache::instance().visualDeckStorage().getVisualDeckStorageAlwaysConvert()) { - return false; - } - - if (!confirmOverwriteIfExists(parent, filePath)) { - return false; - } - - return convert(); - } - - // Show the dialog to the user - DialogConvertDeckToCodFormat conversionDialog(parent); - if (conversionDialog.exec() != QDialog::Accepted) { - SettingsCache::instance().visualDeckStorage().setVisualDeckStoragePromptForConversion( - !conversionDialog.dontAskAgain()); - SettingsCache::instance().visualDeckStorage().setVisualDeckStorageAlwaysConvert(false); - - return false; - } - - // Try to convert file - if (!confirmOverwriteIfExists(parent, filePath)) { - return false; - } - - if (!convert()) { - return false; - } - - if (conversionDialog.dontAskAgain()) { - SettingsCache::instance().visualDeckStorage().setVisualDeckStoragePromptForConversion(false); - SettingsCache::instance().visualDeckStorage().setVisualDeckStorageAlwaysConvert(true); - } - - return true; -} diff --git a/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.h b/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.h index 526582135..6642ad8c6 100644 --- a/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.h +++ b/cockatrice/src/interface/widgets/dialogs/dlg_convert_deck_to_cod_format.h @@ -13,9 +13,6 @@ #include #include #include -#include - -class QWidget; class DialogConvertDeckToCodFormat : public QDialog { @@ -27,21 +24,6 @@ public: [[nodiscard]] bool dontAskAgain() const; - /** - * @brief Checks whether the deck file at \a filePath can store tags. - * - * If the file is not a .cod deck, prompts the user for conversion to the - * Cockatrice format, honoring the saved "always convert / don't ask again" - * preference. On acceptance \a convert is called to perform the conversion. - * - * @param parent The widget to parent the prompt to. - * @param filePath The path of the deck file to check. - * @param convert Called to convert the deck once the user agrees. - * @return true if tags can be stored (no conversion needed, or the conversion - * was performed), false if the user declined to convert. - */ - static bool promptIfRequired(QWidget *parent, const QString &filePath, const std::function &convert); - private: QVBoxLayout *layout; QLabel *label; diff --git a/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp b/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp index fb610e814..f6f34a6a5 100644 --- a/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp +++ b/cockatrice/src/interface/widgets/server/user/user_info_popup.cpp @@ -525,13 +525,6 @@ void UserInfoPopup::rebuildActionButtons(const ServerInfo_User &userInfo, bool o connect(games, &QPushButton::clicked, this, [this, name] { emit showGamesRequested(name); }); add(games); - // ── Invite (only while the inviter has a joinable game for this user) ──── - if (!isSelf && online && gameInviteAvailable && gameInviteAvailable(name)) { - auto *invite = makeBtn(tr("Invite"), tr("Invite to your game"), actionArea, theme); - connect(invite, &QPushButton::clicked, this, [this, name] { emit inviteRequested(name); }); - add(invite); - } - // ── Buddy / ignore (registered users only) ──────────────────────────────── if (!isSelf && isReg) { if (isBuddy) { diff --git a/cockatrice/src/interface/widgets/server/user/user_info_popup.h b/cockatrice/src/interface/widgets/server/user/user_info_popup.h index ed7320fba..02cc2b44e 100644 --- a/cockatrice/src/interface/widgets/server/user/user_info_popup.h +++ b/cockatrice/src/interface/widgets/server/user/user_info_popup.h @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -150,17 +149,6 @@ public: /** Re-pulls the avatar/card art for the currently shown user (e.g. after it loads). */ void refreshHeader(); - /** - * Sets a predicate evaluated on every action-button rebuild. It receives - * the name of the user the popup currently shows; when it returns true an - * "Invite" button is shown. The popup itself never resolves the invite - * link, it just forwards the request. - */ - void setGameInviteAvailable(std::function available) - { - gameInviteAvailable = std::move(available); - } - signals: void mouseEnteredPopup(); void mouseLeftPopup(); @@ -171,7 +159,6 @@ signals: // ── Action signals — connect to UserContextMenu::exec*() ────────────────── void chatRequested(const QString &userName); - void inviteRequested(const QString &userName); void detailsRequested(const QString &userName); void showGamesRequested(const QString &userName); void addBuddyRequested(const QString &userName); @@ -213,7 +200,6 @@ private: QString currentUser; ServerInfo_User currentUserInfo; bool currentOnline = false; - std::function gameInviteAvailable; UserInfoHeaderWidget *header; QWidget *actionArea; ///< rebuilt per user diff --git a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp index a8c99c979..2cacfc4f9 100644 --- a/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp +++ b/cockatrice/src/interface/widgets/server/user/user_list_widget.cpp @@ -345,11 +345,6 @@ UserListWidget::UserListWidget(TabSupervisor *_tabSupervisor, &cardArtProvider->cache(), &cardArtParamsMap, window()); // parented to main window so it floats above siblings - // The invite availability is scoped to the room this list belongs to, - // and gated on the room's buddy-only setting for the hovered user. - userInfoPopup->setGameInviteAvailable( - [this](const QString &userName) { return userContextMenu->hasGameInviteLink(userName); }); - userInfoPopup->hide(); userInfoPopup->setWindowOpacity(0.0); userInfoPopup->installEventFilter(this); @@ -667,8 +662,6 @@ void UserListWidget::connectPopupSignals() // Wire all action signals to UserContextMenu::exec*() connect(userInfoPopup, &UserInfoPopup::chatRequested, userContextMenu, &UserContextMenu::execChat); - connect(userInfoPopup, &UserInfoPopup::inviteRequested, this, - [this](const QString &userName) { userContextMenu->execInvite(userName); }); connect(userInfoPopup, &UserInfoPopup::detailsRequested, userContextMenu, &UserContextMenu::execDetails); connect(userInfoPopup, &UserInfoPopup::showGamesRequested, userContextMenu, &UserContextMenu::execShowGames); connect(userInfoPopup, &UserInfoPopup::addBuddyRequested, userContextMenu, &UserContextMenu::execAddToBuddy); diff --git a/cockatrice/src/interface/widgets/server/user/user_list_widget.h b/cockatrice/src/interface/widgets/server/user/user_list_widget.h index 412271160..7531ef925 100644 --- a/cockatrice/src/interface/widgets/server/user/user_list_widget.h +++ b/cockatrice/src/interface/widgets/server/user/user_list_widget.h @@ -22,7 +22,6 @@ #include #include #include -#include #include class QTreeWidget; diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index b0dac3e7c..f96c139b3 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -1091,8 +1091,7 @@ QList TabSupervisor::getGameInviteLinksForRoom(int roomId) con // The inviter may be in several games of the same room (hosting one and // spectating another, for example). Return every game so the caller can // let the user choose which one to invite to. - for (auto it = gameTabs.cbegin(); it != gameTabs.cend(); ++it) { - TabGame *tab = it.value(); + for (TabGame *tab : gameTabs) { GameMetaInfo *metaInfo = tab->getGame()->getGameMetaInfo(); if (metaInfo->proto().room_id() != roomId) { continue; diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp index 876fbf6ad..04dcdf7f2 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp @@ -10,6 +10,8 @@ #include "../visual_deck_storage_widget.h" #include "deck_preview_deck_tags_display_widget.h" +#include +#include #include #include #include @@ -497,6 +499,21 @@ void DeckPreviewWidget::actDeleteFile() // The folder widget removes this preview once the row is gone. } +static bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath) +{ + QFileInfo fileInfo(filePath); + QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod"); + + if (QFile::exists(newFileName)) { + QMessageBox::StandardButton reply = + QMessageBox::question(parent, QObject::tr("Overwrite Existing File?"), + QObject::tr("A .cod version of this deck already exists. Overwrite it?"), + QMessageBox::Yes | QMessageBox::No); + return reply == QMessageBox::Yes; + } + return true; // Safe to proceed +} + /** * Checks if the deck's file format supports tags. * If not, then prompt the user for file conversion. @@ -504,8 +521,45 @@ void DeckPreviewWidget::actDeleteFile() */ bool DeckPreviewWidget::promptFileConversionIfRequired() { - return DialogConvertDeckToCodFormat::promptIfRequired(this, filePath, [this] { + if (DeckFileFormat::getFormatFromName(filePath) == DeckFileFormat::Cockatrice) { + return true; + } + + // Retrieve saved preference if the prompt is disabled + if (!SettingsCache::instance().visualDeckStorage().getVisualDeckStoragePromptForConversion()) { + if (!SettingsCache::instance().visualDeckStorage().getVisualDeckStorageAlwaysConvert()) { + return false; + } + + if (!confirmOverwriteIfExists(this, filePath)) { + return false; + } + model->convertToCockatriceFormat(row()); return true; - }); + } + + // Show the dialog to the user + DialogConvertDeckToCodFormat conversionDialog(this); + if (conversionDialog.exec() != QDialog::Accepted) { + SettingsCache::instance().visualDeckStorage().setVisualDeckStoragePromptForConversion( + !conversionDialog.dontAskAgain()); + SettingsCache::instance().visualDeckStorage().setVisualDeckStorageAlwaysConvert(false); + + return false; + } + + // Try to convert file + if (!confirmOverwriteIfExists(this, filePath)) { + return false; + } + + model->convertToCockatriceFormat(row()); + + if (conversionDialog.dontAskAgain()) { + SettingsCache::instance().visualDeckStorage().setVisualDeckStoragePromptForConversion(false); + SettingsCache::instance().visualDeckStorage().setVisualDeckStorageAlwaysConvert(true); + } + + return true; }