linking refactor

This commit is contained in:
GenevensiS
2026-02-01 17:39:33 +01:00
parent 7fde6b2605
commit 11e506739a
18 changed files with 411 additions and 407 deletions
+89 -80
View File
@@ -22,66 +22,74 @@ AddCardAction::AddCardAction(Set& set)
, action(ADD, make_intrusive<Card>(*set.game), set.cards)
{}
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const CardP& card)
: CardListAction(set)
, action(ar, card, set.cards)
{}
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>& cards)
: CardListAction(set)
, action(ar, cards, set.cards)
{}
{
// If we are adding cards, resolve any uid conflicts
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
// and never because two different cards randomly got assigned the same uid
if (!action.adding) return;
// Tally existing unique ids
unordered_map<String, CardP> all_existing_cards;
unordered_set<String> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_cards.insert({ card->uid, card });
all_existing_uids.insert(card->uid);
}
// Tally added unique ids
unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
CardP card = action.steps[pos].item;
all_added_uids.insert({ card->uid, card });
}
// Cycle on the added cards
unordered_map<String, CardP> all_added_uids_copy(all_added_uids);
FOR_EACH(added_pair, all_added_uids_copy) {
String old_uid = added_pair.first;
CardP added_card = added_pair.second;
// Assign new unique id if necessary
if (all_existing_cards.find(old_uid) == all_existing_cards.end()) continue;
String new_uid = generate_uid();
added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card });
// Update links on linked cards
LINK_PAIRS(linked_pairs, added_card);
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (linked_uid.empty()) continue;
// If it's an added card, replace the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLinkedUID(old_uid, new_uid);
}
// Otherwise, if it's an existing card, create an action to copy the link
else if (all_existing_cards.find(linked_uid) != all_existing_cards.end()) {
CardP linked_card = all_existing_cards.at(linked_uid);
int linked_index = linked_card->findFreeLink(new_uid, all_existing_uids);
if (linked_index < 0) {
queue_message(MESSAGE_WARNING, _ERROR_1_("not enough free links", linked_card->identification()));
}
else {
String relation(linked_card->getLinkedRelation(linked_index));
card_link_actions.push_back(make_intrusive<OneWayLinkCardsAction>(set, linked_card, new_uid, relation, linked_index));
}
}
}
}
}
String AddCardAction::getName(bool to_undo) const {
return action.getName();
}
void AddCardAction::perform(bool to_undo) {
// If we are adding cards, resolve any uid conflicts
// (If we are re-adding cards, from a remove undo, there shouldn't be any uid conflicts)
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
// and never because two different cards randomly got assigned the same uid
if (action.adding && !to_undo) {
// Tally existing unique ids
unordered_map<String, CardP> all_existing_uids;
FOR_EACH(card, set.cards) {
all_existing_uids.insert({ card->uid, card });
}
// Tally added unique ids
unordered_map<String, CardP> all_added_uids;
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
CardP card = action.steps[pos].item;
all_added_uids.insert({ card->uid, card });
}
FOR_EACH(added_pair, all_added_uids) {
String old_uid = added_pair.first;
CardP added_card = added_pair.second;
// Assign new unique ids
if (all_existing_uids.find(old_uid) != all_existing_uids.end()) {
String new_uid = generate_uid();
added_card->uid = new_uid;
all_added_uids.insert({ new_uid, added_card });
// Update links on linked cards
OTHER_LINKED_PAIRS(linked_pairs, added_card);
FOR_EACH(linked_pair, linked_pairs) {
String& linked_uid = linked_pair.first.get();
String& linked_relation = linked_pair.second.get();
if (linked_uid.empty()) continue;
// If it's an added card, replace the link
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
all_added_uids.at(linked_uid)->updateLink(old_uid, new_uid);
}
// Otherwise, if it's an existing card, copy the link
else if (all_existing_uids.find(linked_uid) != all_existing_uids.end()) {
all_existing_uids.at(linked_uid)->copyLink(set, old_uid, new_uid);
}
}
}
}
}
// Add or remove cards
action.perform(set.cards, to_undo);
// Update card links
for (int i = 0; i < card_link_actions.size(); ++i) {
card_link_actions[i]->perform(to_undo);
}
}
// ----------------------------------------------------------------------------- : Reorder cards
@@ -108,39 +116,40 @@ void ReorderCardsAction::perform(bool to_undo) {
// ----------------------------------------------------------------------------- : Link cards
LinkCardsAction::LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
: CardListAction(set), selected_card(selected_card), linked_cards(linked_cards), selected_relation(selected_relation), linked_relation(linked_relation)
{}
OneWayLinkCardsAction::OneWayLinkCardsAction(Set& set, CardP& card, const String& uid, const String& relation, int index)
: CardListAction(set), card(card), uid(uid), relation(relation)
{
switch (index) {
case 1: {
linked_uid = &card->linked_card_1;
linked_relation = &card->linked_relation_1;
return;
}
case 2: {
linked_uid = &card->linked_card_2;
linked_relation = &card->linked_relation_2;
return;
}
case 3: {
linked_uid = &card->linked_card_3;
linked_relation = &card->linked_relation_3;
return;
}
default: {
linked_uid = &card->linked_card_4;
linked_relation = &card->linked_relation_4;
return;
}
}
}
String LinkCardsAction::getName(bool to_undo) const {
return _("Link cards");
String OneWayLinkCardsAction::getName(bool to_undo) const {
return _("Change link");
}
void LinkCardsAction::perform(bool to_undo) {
if (!to_undo) {
selected_card->link(set, linked_cards, selected_relation, linked_relation);
} else {
selected_card->unlink(linked_cards);
}
}
UnlinkCardsAction::UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card)
: CardListAction(set), selected_card(selected_card), unlinked_card(unlinked_card)
{}
String UnlinkCardsAction::getName(bool to_undo) const {
return _("Unlink card");
}
void UnlinkCardsAction::perform(bool to_undo) {
if (!to_undo) {
pair<String, String> relations = selected_card->unlink(unlinked_card);
selected_relation = relations.first;
unlinked_relation = relations.second;
}
else {
selected_card->link(set, unlinked_card, selected_relation, unlinked_relation);
}
void OneWayLinkCardsAction::perform(bool to_undo) {
swap(*linked_uid, uid);
swap(*linked_relation, relation);
}
// ----------------------------------------------------------------------------- : Change stylesheet
@@ -236,7 +245,7 @@ String ChangeCardUIDAction::getName(bool to_undo) const {
}
void ChangeCardUIDAction::perform(bool to_undo) {
FOR_EACH(c, set.cards) {
c->updateLink(card->uid, uid);
c->updateLinkedUID(card->uid, uid);
}
swap(card->uid, uid);
}