Lazy loading of card database view => faster startup times

This commit is contained in:
Fabio Bas 2015-08-26 23:26:39 +02:00
parent c917a6c272
commit fddcbb8296
8 changed files with 84 additions and 53 deletions

View file

@ -157,8 +157,7 @@ void SetList::guessSortKeys()
} }
} }
CardInfo::CardInfo(CardDatabase *_db, CardInfo::CardInfo(const QString &_name,
const QString &_name,
bool _isToken, bool _isToken,
const QString &_manacost, const QString &_manacost,
const QString &_cmc, const QString &_cmc,
@ -176,8 +175,7 @@ CardInfo::CardInfo(CardDatabase *_db,
const QStringMap &_customPicURLs, const QStringMap &_customPicURLs,
MuidMap _muIds MuidMap _muIds
) )
: db(_db), : name(_name),
name(_name),
isToken(_isToken), isToken(_isToken),
sets(_sets), sets(_sets),
manacost(_manacost), manacost(_manacost),
@ -188,6 +186,7 @@ CardInfo::CardInfo(CardDatabase *_db,
colors(_colors), colors(_colors),
relatedCards(_relatedCards), relatedCards(_relatedCards),
reverseRelatedCards(_reverseRelatedCards), reverseRelatedCards(_reverseRelatedCards),
setsNames(),
upsideDownArt(_upsideDownArt), upsideDownArt(_upsideDownArt),
loyalty(_loyalty), loyalty(_loyalty),
customPicURLs(_customPicURLs), customPicURLs(_customPicURLs),
@ -200,6 +199,8 @@ CardInfo::CardInfo(CardDatabase *_db,
for (int i = 0; i < sets.size(); i++) for (int i = 0; i < sets.size(); i++)
sets[i]->append(this); sets[i]->append(this);
refreshCachedSetNames();
} }
CardInfo::~CardInfo() CardInfo::~CardInfo()
@ -249,6 +250,21 @@ void CardInfo::addToSet(CardSet *set)
{ {
set->append(this); set->append(this);
sets << set; 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) { QString CardInfo::simplifyName(const QString &name) {
@ -330,10 +346,7 @@ CardDatabase::CardDatabase(QObject *parent)
connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase())); connect(settingsCache, SIGNAL(cardDatabasePathChanged()), this, SLOT(loadCardDatabase()));
connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase())); connect(settingsCache, SIGNAL(tokenDatabasePathChanged()), this, SLOT(loadTokenDatabase()));
loadCardDatabase(); noCard = new CardInfo();
loadTokenDatabase();
noCard = new CardInfo(this);
} }
CardDatabase::~CardDatabase() CardDatabase::~CardDatabase()
@ -506,7 +519,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens)
} }
if (isToken == 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); return cardMap.value(cardName);
if (createIfNotFound) { if (createIfNotFound) {
CardInfo *newCard = new CardInfo(this, cardName, true); CardInfo *newCard = new CardInfo(cardName, true);
newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME)); newCard->addToSet(getSet(CardDatabase::TOKENS_SETNAME));
cardMap.insert(cardName, newCard); cardMap.insert(cardName, newCard);
return newCard; return newCard;
@ -619,23 +632,22 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path, bool tokens)
emit cardListChanged(); emit cardListChanged();
} }
if (!tokens) { if (!tokens)
loadStatus = tempLoadStatus; loadStatus = tempLoadStatus;
qDebug() << "loadCardDatabase(): Path = " << path << " Status = " << loadStatus;
}
qDebug() << "loadCardDatabase(): Path =" << path << "Tokens =" << tokens << "Status =" << loadStatus;
return tempLoadStatus; 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) void CardDatabase::loadCustomCardDatabases(const QString &path)

View file

@ -60,8 +60,6 @@ public:
class CardInfo : public QObject { class CardInfo : public QObject {
Q_OBJECT Q_OBJECT
private: private:
CardDatabase *db;
QString name; QString name;
/* /*
@ -84,6 +82,7 @@ private:
QStringList reverseRelatedCards; QStringList reverseRelatedCards;
// the cards thare are reverse-related to me // the cards thare are reverse-related to me
QStringList reverseRelatedCardsToMe; QStringList reverseRelatedCardsToMe;
QString setsNames;
bool upsideDownArt; bool upsideDownArt;
int loyalty; int loyalty;
QStringMap customPicURLs; QStringMap customPicURLs;
@ -92,9 +91,9 @@ private:
int tableRow; int tableRow;
QString pixmapCacheKey; QString pixmapCacheKey;
void refreshCachedSetNames();
public: public:
CardInfo(CardDatabase *_db, CardInfo(const QString &_name = QString(),
const QString &_name = QString(),
bool _isToken = false, bool _isToken = false,
const QString &_manacost = QString(), const QString &_manacost = QString(),
const QString &_cmc = QString(), const QString &_cmc = QString(),
@ -113,14 +112,15 @@ public:
MuidMap muids = MuidMap() MuidMap muids = MuidMap()
); );
~CardInfo(); ~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; } const QString &getSimpleName() const { return simpleName; }
bool getIsToken() const { return isToken; } bool getIsToken() const { return isToken; }
const SetList &getSets() const { return sets; } const SetList &getSets() const { return sets; }
const QString &getManaCost() const { return manacost; } inline const QString &getManaCost() const { return manacost; }
const QString &getCmc() const { return cmc; } inline const QString &getCmc() const { return cmc; }
const QString &getCardType() const { return cardtype; } inline const QString &getCardType() const { return cardtype; }
const QString &getPowTough() const { return powtough; } inline const QString &getPowTough() const { return powtough; }
const QString &getText() const { return text; } const QString &getText() const { return text; }
const QString &getPixmapCacheKey() const { return pixmapCacheKey; } const QString &getPixmapCacheKey() const { return pixmapCacheKey; }
const int &getLoyalty() const { return loyalty; } const int &getLoyalty() const { return loyalty; }
@ -229,12 +229,12 @@ public:
bool hasDetectedFirstRun(); bool hasDetectedFirstRun();
void refreshCachedReverseRelatedCards(); void refreshCachedReverseRelatedCards();
public slots: public slots:
LoadStatus loadCardDatabase(const QString &path, bool tokens = false); LoadStatus loadCardDatabase();
LoadStatus loadTokenDatabase();
void loadCustomCardDatabases(const QString &path); void loadCustomCardDatabases(const QString &path);
void emitCardListChanged(); void emitCardListChanged();
private slots: private slots:
void loadCardDatabase(); LoadStatus loadCardDatabase(const QString &path, bool tokens = false);
void loadTokenDatabase();
signals: signals:
void cardListChanged(); void cardListChanged();
void cardAdded(CardInfo *card); void cardAdded(CardInfo *card);

View file

@ -28,26 +28,16 @@ int CardDatabaseModel::columnCount(const QModelIndex &/*parent*/) const
QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const
{ {
if (!index.isValid()) if (!index.isValid() ||
return QVariant(); index.row() >= cardList.size() ||
if ((index.row() >= cardList.size()) || (index.column() >= CARDDBMODEL_COLUMNS)) index.column() >= CARDDBMODEL_COLUMNS ||
return QVariant(); (role != Qt::DisplayRole && role != SortRole))
if (role != Qt::DisplayRole && role != SortRole)
return QVariant(); return QVariant();
CardInfo *card = cardList.at(index.row()); CardInfo *card = cardList.at(index.row());
switch (index.column()){ switch (index.column()){
case NameColumn: return card->getName(); case NameColumn: return card->getName();
case SetListColumn: { case SetListColumn: return card->getSetsNames();
QStringList setList;
const QList<CardSet *> &sets = card->getSets();
for (int i = 0; i < sets.size(); i++)
{
if(sets[i]->getEnabled())
setList << sets[i]->getShortName();
}
return setList.join(", ");
}
case ManaCostColumn: return role == SortRole ? case ManaCostColumn: return role == SortRole ?
QString("%1%2").arg(card->getCmc(), 4, QChar('0')).arg(card->getManaCost()) : QString("%1%2").arg(card->getCmc(), 4, QChar('0')).arg(card->getManaCost()) :
card->getManaCost(); card->getManaCost();
@ -139,8 +129,30 @@ CardDatabaseDisplayModel::CardDatabaseDisplayModel(QObject *parent)
filterTree = NULL; filterTree = NULL;
setFilterCaseSensitivity(Qt::CaseInsensitive); setFilterCaseSensitivity(Qt::CaseInsensitive);
setSortCaseSensitivity(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 { bool CardDatabaseDisplayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const {

View file

@ -42,6 +42,7 @@ private:
QString searchTerm; QString searchTerm;
QSet<QString> cardNameSet, cardTypes, cardColors; QSet<QString> cardNameSet, cardTypes, cardColors;
FilterTree *filterTree; FilterTree *filterTree;
int loadedRowCount;
public: public:
CardDatabaseDisplayModel(QObject *parent = 0); CardDatabaseDisplayModel(QObject *parent = 0);
void setFilterTree(FilterTree *filterTree); void setFilterTree(FilterTree *filterTree);
@ -54,9 +55,13 @@ public:
void setCardTypes(const QSet<QString> &_cardTypes) { cardTypes = _cardTypes; invalidate(); } void setCardTypes(const QSet<QString> &_cardTypes) { cardTypes = _cardTypes; invalidate(); }
void setCardColors(const QSet<QString> &_cardColors) { cardColors = _cardColors; invalidate(); } void setCardColors(const QSet<QString> &_cardColors) { cardColors = _cardColors; invalidate(); }
void clearFilterAll(); void clearFilterAll();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
protected: protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
bool canFetchMore(const QModelIndex &parent) const;
void fetchMore(const QModelIndex &parent);
private slots: private slots:
void filterTreeChanged(); void filterTreeChanged();
}; };

View file

@ -145,7 +145,7 @@ void DlgEditTokens::actAddToken()
if (name.isEmpty()) if (name.isEmpty())
return; return;
CardInfo *card = new CardInfo(cardDatabaseModel->getDatabase(), name, true); CardInfo *card = new CardInfo(name, true);
card->addToSet(cardDatabaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME)); card->addToSet(cardDatabaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
card->setCardType("Token"); card->setCardType("Token");
cardDatabaseModel->getDatabase()->addCard(card); cardDatabaseModel->getDatabase()->addCard(card);

View file

@ -163,12 +163,15 @@ int main(int argc, char *argv[])
#else #else
const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first(); const QString dataDir = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first();
#endif #endif
if (!db->getLoadSuccess()) if (settingsCache->getCardDatabasePath().isEmpty() ||
if (!db->loadCardDatabase(dataDir + "/cards.xml")) db->loadCardDatabase() != Ok)
settingsCache->setCardDatabasePath(dataDir + "/cards.xml"); settingsCache->setCardDatabasePath(dataDir + "/cards.xml");
if (settingsCache->getTokenDatabasePath().isEmpty())
if (settingsCache->getTokenDatabasePath().isEmpty() ||
db->loadTokenDatabase() != Ok)
settingsCache->setTokenDatabasePath(dataDir + "/tokens.xml"); settingsCache->setTokenDatabasePath(dataDir + "/tokens.xml");
if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty()) { if (!QDir(settingsCache->getDeckPath()).exists() || settingsCache->getDeckPath().isEmpty()) {
QDir().mkpath(dataDir + "/decks"); QDir().mkpath(dataDir + "/decks");
settingsCache->setDeckPath(dataDir + "/decks"); settingsCache->setDeckPath(dataDir + "/decks");

View file

@ -367,17 +367,16 @@ void TabDeckEditor::createCentralFrame()
databaseDisplayModel = new CardDatabaseDisplayModel(this); databaseDisplayModel = new CardDatabaseDisplayModel(this);
databaseDisplayModel->setSourceModel(databaseModel); databaseDisplayModel->setSourceModel(databaseModel);
databaseDisplayModel->setFilterKeyColumn(0); databaseDisplayModel->setFilterKeyColumn(0);
databaseDisplayModel->sort(0, Qt::AscendingOrder);
databaseView = new QTreeView(); databaseView = new QTreeView();
databaseView->setObjectName("databaseView"); databaseView->setObjectName("databaseView");
databaseView->setFocusProxy(searchEdit); databaseView->setFocusProxy(searchEdit);
databaseView->setModel(databaseDisplayModel);
databaseView->setUniformRowHeights(true); databaseView->setUniformRowHeights(true);
databaseView->setRootIsDecorated(false); databaseView->setRootIsDecorated(false);
databaseView->setAlternatingRowColors(true); databaseView->setAlternatingRowColors(true);
databaseView->setSortingEnabled(true); databaseView->setSortingEnabled(true);
databaseView->sortByColumn(0, Qt::AscendingOrder); databaseView->sortByColumn(0, Qt::AscendingOrder);
databaseView->setModel(databaseDisplayModel);
databaseView->resizeColumnToContents(0); databaseView->resizeColumnToContents(0);
connect(databaseView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(updateCardInfoLeft(const QModelIndex &, const QModelIndex &))); 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())); connect(databaseView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(actAddCard()));

View file

@ -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")); 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 // 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; int tableRow = 1;
QString mainCardType = card->getMainCardType(); QString mainCardType = card->getMainCardType();
if ((mainCardType == "Land") || mArtifact) if ((mainCardType == "Land") || mArtifact)