From fddcbb82964dedfbd08daa77a1444a422cad12c8 Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Wed, 26 Aug 2015 23:26:39 +0200 Subject: [PATCH] Lazy loading of card database view => faster startup times --- cockatrice/src/carddatabase.cpp | 46 ++++++++++++++++++---------- cockatrice/src/carddatabase.h | 24 +++++++-------- cockatrice/src/carddatabasemodel.cpp | 42 ++++++++++++++++--------- cockatrice/src/carddatabasemodel.h | 5 +++ cockatrice/src/dlg_edit_tokens.cpp | 2 +- cockatrice/src/main.cpp | 13 +++++--- cockatrice/src/tab_deck_editor.cpp | 3 +- oracle/src/oracleimporter.cpp | 2 +- 8 files changed, 84 insertions(+), 53 deletions(-) diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 41a4976e..ae4bbab8 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -157,8 +157,7 @@ void SetList::guessSortKeys() } } -CardInfo::CardInfo(CardDatabase *_db, - const QString &_name, +CardInfo::CardInfo(const QString &_name, bool _isToken, const QString &_manacost, const QString &_cmc, @@ -176,8 +175,7 @@ CardInfo::CardInfo(CardDatabase *_db, const QStringMap &_customPicURLs, MuidMap _muIds ) - : db(_db), - name(_name), + : name(_name), isToken(_isToken), sets(_sets), manacost(_manacost), @@ -188,6 +186,7 @@ CardInfo::CardInfo(CardDatabase *_db, colors(_colors), relatedCards(_relatedCards), reverseRelatedCards(_reverseRelatedCards), + setsNames(), upsideDownArt(_upsideDownArt), loyalty(_loyalty), customPicURLs(_customPicURLs), @@ -200,6 +199,8 @@ CardInfo::CardInfo(CardDatabase *_db, for (int i = 0; i < sets.size(); i++) sets[i]->append(this); + + refreshCachedSetNames(); } CardInfo::~CardInfo() @@ -249,6 +250,21 @@ void CardInfo::addToSet(CardSet *set) { set->append(this); sets << set; + + refreshCachedSetNames(); +} + +void CardInfo::refreshCachedSetNames() +{ + // update the cached list of set names + QStringList setList; + for (int i = 0; i < sets.size(); i++) + { + if(sets[i]->getEnabled()) + setList << sets[i]->getShortName(); + } + setsNames = setList.join(", "); + } QString CardInfo::simplifyName(const QString &name) { @@ -330,10 +346,7 @@ CardDatabase::CardDatabase(QObject *parent) connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase())); connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase())); - loadCardDatabase(); - loadTokenDatabase(); - - noCard = new CardInfo(this); + noCard = new CardInfo(); } CardDatabase::~CardDatabase() @@ -506,7 +519,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) } if (isToken == tokens) { - addCard(new CardInfo(this, name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, muids)); + addCard(new CardInfo(name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown, loyalty, cipt, tableRow, sets, customPicURLs, muids)); } } } @@ -517,7 +530,7 @@ CardInfo *CardDatabase::getCardFromMap(CardNameMap &cardMap, const QString &card return cardMap.value(cardName); if (createIfNotFound) { - CardInfo *newCard = new CardInfo(this, cardName, true); + CardInfo *newCard = new CardInfo(cardName, true); newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME)); cardMap.insert(cardName, newCard); return newCard; @@ -619,23 +632,22 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens) emit cardListChanged(); } - if (!tokens) { + if (!tokens) loadStatus = tempLoadStatus; - qDebug() << "loadCardDatabase(): Path = " << path << " Status = " << loadStatus; - } + qDebug() << "loadCardDatabase(): Path =" << path << "Tokens =" << tokens << "Status =" << loadStatus; return tempLoadStatus; } -void CardDatabase::loadCardDatabase() +LoadStatus CardDatabase::loadCardDatabase() { - loadCardDatabase(settingsCache->getCardDatabasePath(), false); + return loadCardDatabase(settingsCache->getCardDatabasePath(), false); } -void CardDatabase::loadTokenDatabase() +LoadStatus CardDatabase::loadTokenDatabase() { - loadCardDatabase(settingsCache->getTokenDatabasePath(), true); + return loadCardDatabase(settingsCache->getTokenDatabasePath(), true); } void CardDatabase::loadCustomCardDatabases(const QString &path) diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index 1cb8544a..fdcfa7df 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -60,8 +60,6 @@ public: class CardInfo : public QObject { Q_OBJECT private: - CardDatabase *db; - QString name; /* @@ -84,6 +82,7 @@ private: QStringList reverseRelatedCards; // the cards thare are reverse-related to me QStringList reverseRelatedCardsToMe; + QString setsNames; bool upsideDownArt; int loyalty; QStringMap customPicURLs; @@ -92,9 +91,9 @@ private: int tableRow; QString pixmapCacheKey; + void refreshCachedSetNames(); public: - CardInfo(CardDatabase *_db, - const QString &_name = QString(), + CardInfo(const QString &_name = QString(), bool _isToken = false, const QString &_manacost = QString(), const QString &_cmc = QString(), @@ -113,14 +112,15 @@ public: MuidMap muids = MuidMap() ); ~CardInfo(); - const QString &getName() const { return name; } + inline const QString &getName() const { return name; } + inline const QString &getSetsNames() const { return setsNames; } const QString &getSimpleName() const { return simpleName; } bool getIsToken() const { return isToken; } const SetList &getSets() const { return sets; } - const QString &getManaCost() const { return manacost; } - const QString &getCmc() const { return cmc; } - const QString &getCardType() const { return cardtype; } - const QString &getPowTough() const { return powtough; } + inline const QString &getManaCost() const { return manacost; } + inline const QString &getCmc() const { return cmc; } + inline const QString &getCardType() const { return cardtype; } + inline const QString &getPowTough() const { return powtough; } const QString &getText() const { return text; } const QString &getPixmapCacheKey() const { return pixmapCacheKey; } const int &getLoyalty() const { return loyalty; } @@ -229,12 +229,12 @@ public: bool hasDetectedFirstRun(); void refreshCachedReverseRelatedCards(); public slots: - LoadStatus loadCardDatabase(const QString &path, bool tokens = false); + LoadStatus loadCardDatabase(); + LoadStatus loadTokenDatabase(); void loadCustomCardDatabases(const QString &path); void emitCardListChanged(); private slots: - void loadCardDatabase(); - void loadTokenDatabase(); + LoadStatus loadCardDatabase(const QString &path, bool tokens = false); signals: void cardListChanged(); void cardAdded(CardInfo *card); diff --git a/cockatrice/src/carddatabasemodel.cpp b/cockatrice/src/carddatabasemodel.cpp index 94939b8b..9b8a89bc 100644 --- a/cockatrice/src/carddatabasemodel.cpp +++ b/cockatrice/src/carddatabasemodel.cpp @@ -28,26 +28,16 @@ int CardDatabaseModel::columnCount(const QModelIndex &/*parent*/) const QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) - return QVariant(); - if ((index.row() >= cardList.size()) || (index.column() >= CARDDBMODEL_COLUMNS)) - return QVariant(); - if (role != Qt::DisplayRole && role != SortRole) + if (!index.isValid() || + index.row() >= cardList.size() || + index.column() >= CARDDBMODEL_COLUMNS || + (role != Qt::DisplayRole && role != SortRole)) return QVariant(); CardInfo *card = cardList.at(index.row()); switch (index.column()){ case NameColumn: return card->getName(); - case SetListColumn: { - QStringList setList; - const QList &sets = card->getSets(); - for (int i = 0; i < sets.size(); i++) - { - if(sets[i]->getEnabled()) - setList << sets[i]->getShortName(); - } - return setList.join(", "); - } + case SetListColumn: return card->getSetsNames(); case ManaCostColumn: return role == SortRole ? QString("%1%2").arg(card->getCmc(), 4, QChar('0')).arg(card->getManaCost()) : card->getManaCost(); @@ -139,8 +129,30 @@ CardDatabaseDisplayModel::CardDatabaseDisplayModel(QObject *parent) filterTree = NULL; setFilterCaseSensitivity(Qt::CaseInsensitive); setSortCaseSensitivity(Qt::CaseInsensitive); + + loadedRowCount = 0; } +bool CardDatabaseDisplayModel::canFetchMore(const QModelIndex & index) const +{ + return loadedRowCount < sourceModel()->rowCount(index); +} + +void CardDatabaseDisplayModel::fetchMore(const QModelIndex & index) +{ + int remainder = sourceModel()->rowCount(index) - loadedRowCount; + int itemsToFetch = qMin(100, remainder); + + beginInsertRows(QModelIndex(), loadedRowCount, loadedRowCount+itemsToFetch-1); + + loadedRowCount += itemsToFetch; + endInsertRows(); +} + +int CardDatabaseDisplayModel::rowCount(const QModelIndex &parent) const +{ + return qMin(QSortFilterProxyModel::rowCount(parent), loadedRowCount); +} bool CardDatabaseDisplayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { diff --git a/cockatrice/src/carddatabasemodel.h b/cockatrice/src/carddatabasemodel.h index 35ec45a9..ba862025 100644 --- a/cockatrice/src/carddatabasemodel.h +++ b/cockatrice/src/carddatabasemodel.h @@ -42,6 +42,7 @@ private: QString searchTerm; QSet cardNameSet, cardTypes, cardColors; FilterTree *filterTree; + int loadedRowCount; public: CardDatabaseDisplayModel(QObject *parent = 0); void setFilterTree(FilterTree *filterTree); @@ -54,9 +55,13 @@ public: void setCardTypes(const QSet &_cardTypes) { cardTypes = _cardTypes; invalidate(); } void setCardColors(const QSet &_cardColors) { cardColors = _cardColors; invalidate(); } void clearFilterAll(); + int rowCount(const QModelIndex &parent = QModelIndex()) const; protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + + bool canFetchMore(const QModelIndex &parent) const; + void fetchMore(const QModelIndex &parent); private slots: void filterTreeChanged(); }; diff --git a/cockatrice/src/dlg_edit_tokens.cpp b/cockatrice/src/dlg_edit_tokens.cpp index 92725866..8cf88ee9 100644 --- a/cockatrice/src/dlg_edit_tokens.cpp +++ b/cockatrice/src/dlg_edit_tokens.cpp @@ -145,7 +145,7 @@ void DlgEditTokens::actAddToken() if (name.isEmpty()) return; - CardInfo *card = new CardInfo(cardDatabaseModel->getDatabase(), name, true); + CardInfo *card = new CardInfo(name, true); card->addToSet(cardDatabaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME)); card->setCardType("Token"); cardDatabaseModel->getDatabase()->addCard(card); diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 10d01bfc..6d1066f1 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -163,12 +163,15 @@ int main(int argc, char *argv[]) #else const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); #endif - - if (!db->getLoadSuccess()) - if (!db->loadCardDatabase(dataDir + "/cards.xml")) - settingsCache->setCardDatabasePath(dataDir + "/cards.xml"); - if (settingsCache->getTokenDatabasePath().isEmpty()) + + if (settingsCache->getCardDatabasePath().isEmpty() || + db->loadCardDatabase() != Ok) + settingsCache->setCardDatabasePath(dataDir + "/cards.xml"); + + if (settingsCache->getTokenDatabasePath().isEmpty() || + db->loadTokenDatabase() != Ok) settingsCache->setTokenDatabasePath(dataDir + "/tokens.xml"); + if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty()) { QDir().mkpath(dataDir + "/decks"); settingsCache->setDeckPath(dataDir + "/decks"); diff --git a/cockatrice/src/tab_deck_editor.cpp b/cockatrice/src/tab_deck_editor.cpp index 1e27434b..771111a2 100644 --- a/cockatrice/src/tab_deck_editor.cpp +++ b/cockatrice/src/tab_deck_editor.cpp @@ -367,17 +367,16 @@ void TabDeckEditor::createCentralFrame() databaseDisplayModel = new CardDatabaseDisplayModel(this); databaseDisplayModel->setSourceModel(databaseModel); databaseDisplayModel->setFilterKeyColumn(0); - databaseDisplayModel->sort(0, Qt::AscendingOrder); databaseView = new QTreeView(); databaseView->setObjectName("databaseView"); databaseView->setFocusProxy(searchEdit); - databaseView->setModel(databaseDisplayModel); databaseView->setUniformRowHeights(true); databaseView->setRootIsDecorated(false); databaseView->setAlternatingRowColors(true); databaseView->setSortingEnabled(true); databaseView->sortByColumn(0, Qt::AscendingOrder); + databaseView->setModel(databaseDisplayModel); databaseView->resizeColumnToContents(0); connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &))); connect(databaseView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actAddCard())); diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 7659f465..f4f8e870 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -96,7 +96,7 @@ CardInfo *OracleImporter::addCard(const QString &setName, bool cipt = cardText.contains("Hideaway") || (cardText.contains(cardName + " enters the battlefield tapped") && !cardText.contains(cardName + " enters the battlefield tapped unless")); // insert the card and its properties - card = new CardInfo(this, cardName, isToken, cardCost, cmc, cardType, cardPT, cardText, colors, relatedCards, reverseRelatedCards, upsideDown, cardLoyalty, cipt); + card = new CardInfo(cardName, isToken, cardCost, cmc, cardType, cardPT, cardText, colors, relatedCards, reverseRelatedCards, upsideDown, cardLoyalty, cipt); int tableRow = 1; QString mainCardType = card->getMainCardType(); if ((mainCardType == "Land") || mArtifact)