From b11d3e0c553ca21686594ce371a901ac297996bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Fri, 7 Feb 2025 07:20:36 +0100 Subject: [PATCH] Bulk editing dialog functionality. --- .../printing_selector/printing_selector.cpp | 4 +- .../src/dialogs/dlg_select_set_for_cards.cpp | 418 ++++++++++-------- .../src/dialogs/dlg_select_set_for_cards.h | 2 + common/decklist.cpp | 15 +- common/decklist.h | 2 +- 5 files changed, 248 insertions(+), 193 deletions(-) diff --git a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp index 3e4a651d7..2252cf707 100644 --- a/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp +++ b/cockatrice/src/client/ui/widgets/printing_selector/printing_selector.cpp @@ -280,5 +280,7 @@ void PrintingSelector::toggleVisibilityNavigationButtons(bool _state) void PrintingSelector::selectSetForCards() { DlgSelectSetForCards *setSelectionDialog = new DlgSelectSetForCards(nullptr, deckModel); - setSelectionDialog->show(); + if (!setSelectionDialog->exec()) { + return; + } } diff --git a/cockatrice/src/dialogs/dlg_select_set_for_cards.cpp b/cockatrice/src/dialogs/dlg_select_set_for_cards.cpp index da2841124..1e6b8f92a 100644 --- a/cockatrice/src/dialogs/dlg_select_set_for_cards.cpp +++ b/cockatrice/src/dialogs/dlg_select_set_for_cards.cpp @@ -7,7 +7,9 @@ #include "dlg_select_set_for_cards.h" #include +#include #include +#include #include #include #include @@ -17,8 +19,7 @@ #include #include -DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_model) - : QDialog(parent), model(_model) +DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_model) : QDialog(parent), model(_model) { setMinimumSize(500, 500); setAcceptDrops(true); @@ -51,7 +52,8 @@ DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_mode uneditedCardsArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); uneditedCardsArea->setWidgetResizable(true); - uneditedCardsFlowWidget = new FlowWidget(uneditedCardsArea, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); + uneditedCardsFlowWidget = + new FlowWidget(uneditedCardsArea, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded); uneditedCardsArea->setWidget(uneditedCardsFlowWidget); bottomLayout->addWidget(uneditedCardsLabel); @@ -65,9 +67,32 @@ DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_mode sortSetsByCount(); updateCardLists(); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOK())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + splitter->addWidget(buttonBox); + // Set stretch factors: top (2:3), bottom (1:3) - splitter->setStretchFactor(0, 3); - splitter->setStretchFactor(1, 1); + splitter->setStretchFactor(0, 6); + splitter->setStretchFactor(1, 2); + splitter->setStretchFactor(2, 1); +} + +void DlgSelectSetForCards::actOK() +{ + QMap modifiedSetsAndCardsMap = getModifiedCards(); + for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) { + for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) { + QModelIndex find_card = model->findCard(card, DECK_ZONE_MAIN); + if (!find_card.isValid()) { + continue; + } + model->removeRow(find_card.row(), find_card.parent()); + model->addCard(card, CardDatabaseManager::getInstance()->getSpecificSetForCard(card, modifiedSet, ""), + DECK_ZONE_MAIN); + } + } + accept(); } void DlgSelectSetForCards::sortSetsByCount() @@ -135,10 +160,10 @@ QMap DlgSelectSetForCards::getSetsForCards() void DlgSelectSetForCards::updateCardLists() { - QList entry_widgets; + QList entry_widgets; for (int i = 0; i < listLayout->count(); ++i) { QWidget *widget = listLayout->itemAt(i)->widget(); - if (auto entry = qobject_cast(widget)) { + if (auto entry = qobject_cast(widget)) { entry_widgets.append(entry); } } @@ -189,8 +214,6 @@ void DlgSelectSetForCards::updateCardLists() } } - - void DlgSelectSetForCards::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-setentrywidget")) { @@ -224,182 +247,6 @@ void DlgSelectSetForCards::dropEvent(QDropEvent *event) event->acceptProposedAction(); } - -SetEntryWidget::SetEntryWidget(DlgSelectSetForCards *_parent, const QString &_setName, int count) - : QWidget(_parent), parent(_parent), setName(_setName), expanded(false) -{ - layout = new QVBoxLayout(this); - setLayout(layout); - - QHBoxLayout *headerLayout = new QHBoxLayout(); - checkBox = new QCheckBox(setName, this); - connect(checkBox, &QCheckBox::checkStateChanged, parent, &DlgSelectSetForCards::updateCardLists); - expandButton = new QPushButton("+", this); - countLabel = new QLabel(QString::number(count), this); - - connect(expandButton, &QPushButton::clicked, this, &SetEntryWidget::toggleExpansion); - - headerLayout->addWidget(checkBox); - headerLayout->addWidget(countLabel); - headerLayout->addWidget(expandButton); - layout->addLayout(headerLayout); - - possibleCardsLabel = new QLabel(this); - possibleCardsLabel->setText("Unselected cards in set:"); - possibleCardsLabel->hide(); - - cardListContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); - cardListContainer->hide(); - - alreadySelectedCardsLabel = new QLabel(this); - alreadySelectedCardsLabel->setText("Cards in set already selected in higher priority set:"); - alreadySelectedCardsLabel->hide(); - - alreadySelectedCardListContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); - alreadySelectedCardListContainer->hide(); - - layout->addWidget(possibleCardsLabel); - layout->addWidget(cardListContainer); - layout->addWidget(alreadySelectedCardsLabel); - layout->addWidget(alreadySelectedCardListContainer); - setAttribute(Qt::WA_DeleteOnClose, false); -} - -void SetEntryWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - QDrag *drag = new QDrag(this); - QMimeData *mimeData = new QMimeData; - - mimeData->setData("application/x-setentrywidget", setName.toUtf8()); - drag->setMimeData(mimeData); - - // Create a drag preview (snapshot of the widget) - QPixmap pixmap(size()); - pixmap.fill(Qt::transparent); // Ensure transparency - - QPainter painter(&pixmap); - this->render(&painter); - painter.end(); - - drag->setPixmap(pixmap); - drag->setHotSpot(event->position().toPoint()); // Keeps the cursor aligned - - drag->exec(Qt::MoveAction); - } -} - - -void SetEntryWidget::mouseMoveEvent(QMouseEvent *event) { - if (!(event->buttons() & Qt::LeftButton)) - return; - - // Start a drag operation - QDrag *drag = new QDrag(this); - QMimeData *mimeData = new QMimeData(); - mimeData->setText("SetEntryWidget Data"); // Customize with relevant data - drag->setMimeData(mimeData); - - // Create a drag preview of the widget - QPixmap pixmap(size()); - pixmap.fill(Qt::transparent); - - // Render the widget onto the pixmap - render(&pixmap); - - // Optionally, apply transparency to make it look like a drag effect - QPixmap transparentPixmap = pixmap; - QPainter painter(&transparentPixmap); - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); - painter.fillRect(transparentPixmap.rect(), QColor(0, 0, 0, 128)); // Semi-transparent effect - painter.end(); - - // Set the drag pixmap - drag->setPixmap(transparentPixmap); - drag->setHotSpot(event->pos()); // Ensure the drag starts from where the user clicked - - // Start the drag operation - drag->exec(Qt::MoveAction); -} - - -bool SetEntryWidget::isChecked() const -{ - return checkBox->isChecked(); -} - -void SetEntryWidget::toggleExpansion() -{ - expanded = !expanded; - possibleCardsLabel->setVisible(expanded); - cardListContainer->setVisible(expanded); - alreadySelectedCardsLabel->setVisible(expanded); - alreadySelectedCardListContainer->setVisible(expanded); - expandButton->setText(expanded ? "-" : "+"); - - parent->updateCardLists(); -} - -QStringList SetEntryWidget::getAllCardsForSet() -{ - QStringList list; - QMap setCards = parent->getCardsForSets(); - if (setCards.contains(setName)) { - for (const QString &cardName : setCards[setName]) { - list << cardName; - } - } - return list; -} - -void SetEntryWidget::populateCardList() -{ - cardListContainer->clearLayout(); - alreadySelectedCardListContainer->clearLayout(); - - QStringList possibleCards = getAllCardsForSet(); - QList entry_widgets; - for (int i = 0; i < parent->listLayout->count(); ++i) { - QWidget *widget = parent->listLayout->itemAt(i)->widget(); - if (auto entry = qobject_cast(widget)) { - entry_widgets.append(entry); - } - } - - for (SetEntryWidget *entryWidget : entry_widgets) { - if (entryWidget == this) { - break; - } - if (entryWidget->isChecked()) { - QStringList alreadyDoneCards = entryWidget->getAllCardsForSet(); - for (const QString &cardName : alreadyDoneCards) { - possibleCards.removeAll(cardName); - } - } - } - - for (const QString &cardName : possibleCards) { - CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(cardListContainer); - picture_widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId( - cardName, - CardDatabaseManager::getInstance()->getSpecificSetForCard(cardName, setName, nullptr).getProperty("uuid"))); - cardListContainer->addWidget(picture_widget); - } - - QStringList unusedCards = getAllCardsForSet(); - for (const QString &cardName : possibleCards) { - unusedCards.removeAll(cardName); - } - - for (const QString &cardName : unusedCards) { - CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(alreadySelectedCardListContainer); - picture_widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId( - cardName, - CardDatabaseManager::getInstance()->getSpecificSetForCard(cardName, setName, nullptr).getProperty("uuid"))); - alreadySelectedCardListContainer->addWidget(picture_widget); - } -} - QMap DlgSelectSetForCards::getCardsForSets() { QMap setCards; @@ -436,3 +283,204 @@ QMap DlgSelectSetForCards::getCardsForSets() } return setCards; } + +QMap DlgSelectSetForCards::getModifiedCards() +{ + QMap modifiedCards; + for (int i = 0; i < listLayout->count(); ++i) { + QWidget *widget = listLayout->itemAt(i)->widget(); + if (auto entry = qobject_cast(widget)) { + if (entry->isChecked()) { + QStringList cardsInSet = entry->getAllCardsForSet(); + + for (QString cardInSet : cardsInSet) { + bool alreadyContained = false; + for (QString key : modifiedCards.keys()) { + if (modifiedCards[key].contains(cardInSet)) { + alreadyContained = true; + } + } + if (!alreadyContained) { + modifiedCards[entry->setName].append(cardInSet); + } + } + } + } + } + return modifiedCards; +} + +SetEntryWidget::SetEntryWidget(DlgSelectSetForCards *_parent, const QString &_setName, int count) + : QWidget(_parent), parent(_parent), setName(_setName), expanded(false) +{ + layout = new QVBoxLayout(this); + setLayout(layout); + + QHBoxLayout *headerLayout = new QHBoxLayout(); + checkBox = new QCheckBox(setName, this); + connect(checkBox, &QCheckBox::checkStateChanged, parent, &DlgSelectSetForCards::updateCardLists); + expandButton = new QPushButton("+", this); + countLabel = new QLabel(QString::number(count), this); + + connect(expandButton, &QPushButton::clicked, this, &SetEntryWidget::toggleExpansion); + + headerLayout->addWidget(checkBox); + headerLayout->addWidget(countLabel); + headerLayout->addWidget(expandButton); + layout->addLayout(headerLayout); + + possibleCardsLabel = new QLabel(this); + possibleCardsLabel->setText("Unselected cards in set:"); + possibleCardsLabel->hide(); + + cardListContainer = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); + cardListContainer->hide(); + + alreadySelectedCardsLabel = new QLabel(this); + alreadySelectedCardsLabel->setText("Cards in set already selected in higher priority set:"); + alreadySelectedCardsLabel->hide(); + + alreadySelectedCardListContainer = + new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAlwaysOff); + alreadySelectedCardListContainer->hide(); + + layout->addWidget(possibleCardsLabel); + layout->addWidget(cardListContainer); + layout->addWidget(alreadySelectedCardsLabel); + layout->addWidget(alreadySelectedCardListContainer); + setAttribute(Qt::WA_DeleteOnClose, false); +} + +void SetEntryWidget::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData; + + mimeData->setData("application/x-setentrywidget", setName.toUtf8()); + drag->setMimeData(mimeData); + + // Create a drag preview (snapshot of the widget) + QPixmap pixmap(size()); + pixmap.fill(Qt::transparent); // Ensure transparency + + QPainter painter(&pixmap); + this->render(&painter); + painter.end(); + + drag->setPixmap(pixmap); + drag->setHotSpot(event->position().toPoint()); // Keeps the cursor aligned + + drag->exec(Qt::MoveAction); + } +} + +void SetEntryWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (!(event->buttons() & Qt::LeftButton)) + return; + + // Start a drag operation + QDrag *drag = new QDrag(this); + QMimeData *mimeData = new QMimeData(); + mimeData->setText("SetEntryWidget Data"); // Customize with relevant data + drag->setMimeData(mimeData); + + // Create a drag preview of the widget + QPixmap pixmap(size()); + pixmap.fill(Qt::transparent); + + // Render the widget onto the pixmap + render(&pixmap); + + // Optionally, apply transparency to make it look like a drag effect + QPixmap transparentPixmap = pixmap; + QPainter painter(&transparentPixmap); + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.fillRect(transparentPixmap.rect(), QColor(0, 0, 0, 128)); // Semi-transparent effect + painter.end(); + + // Set the drag pixmap + drag->setPixmap(transparentPixmap); + drag->setHotSpot(event->pos()); // Ensure the drag starts from where the user clicked + + // Start the drag operation + drag->exec(Qt::MoveAction); +} + +bool SetEntryWidget::isChecked() const +{ + return checkBox->isChecked(); +} + +void SetEntryWidget::toggleExpansion() +{ + expanded = !expanded; + possibleCardsLabel->setVisible(expanded); + cardListContainer->setVisible(expanded); + alreadySelectedCardsLabel->setVisible(expanded); + alreadySelectedCardListContainer->setVisible(expanded); + expandButton->setText(expanded ? "-" : "+"); + + parent->updateCardLists(); +} + +QStringList SetEntryWidget::getAllCardsForSet() +{ + QStringList list; + QMap setCards = parent->getCardsForSets(); + if (setCards.contains(setName)) { + for (const QString &cardName : setCards[setName]) { + list << cardName; + } + } + return list; +} + +void SetEntryWidget::populateCardList() +{ + cardListContainer->clearLayout(); + alreadySelectedCardListContainer->clearLayout(); + + QStringList possibleCards = getAllCardsForSet(); + QList entry_widgets; + for (int i = 0; i < parent->listLayout->count(); ++i) { + QWidget *widget = parent->listLayout->itemAt(i)->widget(); + if (auto entry = qobject_cast(widget)) { + entry_widgets.append(entry); + } + } + + for (SetEntryWidget *entryWidget : entry_widgets) { + if (entryWidget == this) { + break; + } + if (entryWidget->isChecked()) { + QStringList alreadyDoneCards = entryWidget->getAllCardsForSet(); + for (const QString &cardName : alreadyDoneCards) { + possibleCards.removeAll(cardName); + } + } + } + + for (const QString &cardName : possibleCards) { + CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(cardListContainer); + picture_widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId( + cardName, + CardDatabaseManager::getInstance()->getSpecificSetForCard(cardName, setName, nullptr).getProperty("uuid"))); + cardListContainer->addWidget(picture_widget); + } + + QStringList unusedCards = getAllCardsForSet(); + for (const QString &cardName : possibleCards) { + unusedCards.removeAll(cardName); + } + + for (const QString &cardName : unusedCards) { + CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(alreadySelectedCardListContainer); + picture_widget->setCard(CardDatabaseManager::getInstance()->getCardByNameAndProviderId( + cardName, + CardDatabaseManager::getInstance()->getSpecificSetForCard(cardName, setName, nullptr).getProperty("uuid"))); + alreadySelectedCardListContainer->addWidget(picture_widget); + } +} diff --git a/cockatrice/src/dialogs/dlg_select_set_for_cards.h b/cockatrice/src/dialogs/dlg_select_set_for_cards.h index 57e02b0ff..b2a068dd8 100644 --- a/cockatrice/src/dialogs/dlg_select_set_for_cards.h +++ b/cockatrice/src/dialogs/dlg_select_set_for_cards.h @@ -22,12 +22,14 @@ public: explicit DlgSelectSetForCards(QWidget *parent, DeckListModel *_model); void sortSetsByCount(); QMap getCardsForSets(); + QMap getModifiedCards(); QVBoxLayout *listLayout; public slots: void updateCardLists(); void dragEnterEvent(QDragEnterEvent *event) override; void dropEvent(QDropEvent *event) override; + void actOK(); private: QVBoxLayout *layout; diff --git a/common/decklist.cpp b/common/decklist.cpp index e72e343b5..a9a825592 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -166,13 +166,16 @@ AbstractDecklistNode *InnerDecklistNode::findCardChildByNameProviderIdAndNumber( const QString &_cardNumber) { for (const auto &i : *this) { - if (i != nullptr && i->getName() == _name) { - if (i->getCardCollectorNumber() == _cardNumber) { - if (i->getCardProviderId() == _providerId) { - return i; - } - } + if (!i || i->getName() != _name) { + continue; } + if (_cardNumber != "" && i->getCardCollectorNumber() != _cardNumber) { + continue; + } + if (_providerId != "" && i->getCardProviderId() != _providerId) { + continue; + } + return i; } return nullptr; } diff --git a/common/decklist.h b/common/decklist.h index 1db3b3991..d7ed4add4 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -137,7 +137,7 @@ public: void clearTree(); AbstractDecklistNode *findChild(const QString &_name); AbstractDecklistNode *findCardChildByNameProviderIdAndNumber(const QString &_name, - const QString &_providerId, + const QString &_providerId = "", const QString &_cardNumber = ""); int height() const override; int recursiveCount(bool countTotalCards = false) const;