#include "card_database_model.h" #include #include #define CARDDBMODEL_COLUMNS 6 CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromEnabledSets, QObject *parent) : QAbstractListModel(parent), db(_db), showOnlyCardsFromEnabledSets(_showOnlyCardsFromEnabledSets) { connect(db, &CardDatabase::cardAdded, this, &CardDatabaseModel::cardAdded); connect(db, &CardDatabase::cardRemoved, this, &CardDatabaseModel::cardRemoved); connect(db, &CardDatabase::cardDatabaseEnabledSetsChanged, this, &CardDatabaseModel::cardDatabaseEnabledSetsChanged); connect(db, &CardDatabase::cardDatabaseReset, this, &CardDatabaseModel::resetCardList); cardDatabaseEnabledSetsChanged(); } CardDatabaseModel::~CardDatabaseModel() = default; int CardDatabaseModel::rowCount(const QModelIndex & /*parent*/) const { return cardList.size(); } int CardDatabaseModel::columnCount(const QModelIndex & /*parent*/) const { return CARDDBMODEL_COLUMNS; } QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= cardList.size() || index.column() >= CARDDBMODEL_COLUMNS || (role != Qt::DisplayRole && role != SortRole)) { return QVariant(); } CardInfoPtr card = cardList.at(index.row()); switch (index.column()) { case NameColumn: return card->getName(); case SetListColumn: return card->getSetsNames(); case ManaCostColumn: return role == SortRole ? QString("%1%2").arg(card->getCmc(), 4, QChar('0')).arg(card->getManaCost()) : card->getManaCost(); case CardTypeColumn: return card->getCardType(); case PTColumn: return card->getPowTough(); case ColorColumn: return card->getColors(); default: return QVariant(); } } QVariant CardDatabaseModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation != Qt::Horizontal) { return QVariant(); } switch (section) { case NameColumn: return QString(tr("Name")); case SetListColumn: return QString(tr("Sets")); case ManaCostColumn: return QString(tr("Mana cost")); case CardTypeColumn: return QString(tr("Card type")); case PTColumn: return QString(tr("P/T")); case ColorColumn: return QString(tr("Color(s)")); default: return QVariant(); } } void CardDatabaseModel::cardInfoChanged(const CardInfoPtr &card) { const int row = cardList.indexOf(card); if (row == -1) { return; } emit dataChanged(index(row, 0), index(row, CARDDBMODEL_COLUMNS - 1)); } bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(const CardInfoPtr &card) const { if (!showOnlyCardsFromEnabledSets) { return true; } for (const auto &printings : card->getSets()) { for (const auto &printing : printings) { if (printing.getSet()->getEnabled()) { return true; } } } return false; } void CardDatabaseModel::cardDatabaseEnabledSetsChanged() { // Build the new card list in a single pass. QList newCardList; newCardList.reserve(cardList.size()); for (const CardInfoPtr &card : cardList) { if (checkCardHasAtLeastOneEnabledSet(card)) { newCardList.append(card); } } for (const CardInfoPtr &card : db->getCardList()) { if (!cardListSet.contains(card) && checkCardHasAtLeastOneEnabledSet(card)) { newCardList.append(card); } } if (newCardList == cardList) { return; } // Rebuild the whole list inside a single model reset instead of emitting // per-card insert/remove notifications. With tens of thousands of cards the // per-card path is the dominant cost of constructing a CardDatabaseModel. QSet oldCardListSet = cardListSet; QSet newCardListSet(newCardList.begin(), newCardList.end()); beginResetModel(); // Disconnect cards that are no longer shown. for (const CardInfoPtr &card : cardList) { if (!newCardListSet.contains(card)) { disconnect(card.data(), nullptr, this, nullptr); } } cardList = newCardList; cardListSet = newCardListSet; // Connect cards that are now shown for the first time. for (const CardInfoPtr &card : cardList) { if (!oldCardListSet.contains(card)) { connect(card.data(), &CardInfo::cardInfoChanged, this, &CardDatabaseModel::cardInfoChanged); } } endResetModel(); } void CardDatabaseModel::cardAdded(const CardInfoPtr &card) { if (checkCardHasAtLeastOneEnabledSet(card)) { // add the card if it's present in at least one enabled set beginInsertRows(QModelIndex(), cardList.size(), cardList.size()); cardList.append(card); cardListSet.insert(card); connect(card.data(), &CardInfo::cardInfoChanged, this, &CardDatabaseModel::cardInfoChanged); endInsertRows(); } } void CardDatabaseModel::cardRemoved(CardInfoPtr card) { const int row = cardList.indexOf(card); if (row == -1) { return; } beginRemoveRows(QModelIndex(), row, row); disconnect(card.data(), nullptr, this, nullptr); cardListSet.remove(card); card.clear(); cardList.removeAt(row); endRemoveRows(); } void CardDatabaseModel::resetCardList() { beginResetModel(); cardList.clear(); cardListSet.clear(); for (const CardInfoPtr &card : db->getCardList()) { if (checkCardHasAtLeastOneEnabledSet(card)) { cardList.append(card); cardListSet.insert(card); connect(card.data(), &CardInfo::cardInfoChanged, this, &CardDatabaseModel::cardInfoChanged); } } endResetModel(); }