diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp index 305cd34d9..3481e245b 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.cpp +++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp @@ -91,6 +91,22 @@ void DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Form }); } +bool DeckLoader::reload() +{ + QString lastFileName = loadedDeck.lastLoadInfo.fileName; + if (lastFileName.isEmpty()) { + return false; + } + std::optional deck = loadFromFile(lastFileName, loadedDeck.lastLoadInfo.fileFormat, false); + + if (!deck) { + return false; + } + + loadedDeck = *deck; + return true; +} + std::optional DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId) { DeckList deckList; diff --git a/cockatrice/src/interface/deck_loader/deck_loader.h b/cockatrice/src/interface/deck_loader/deck_loader.h index 1780e2706..2530b7f5d 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.h +++ b/cockatrice/src/interface/deck_loader/deck_loader.h @@ -62,6 +62,13 @@ public: */ void loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest); + /** + * @brief Loads the file that the lastLoadInfo currently points to into this instance. + * No-ops if the lastLoadInfo is missing the required info or the load fails. + * @return Whether the loaded succeeded. + */ + bool reload(); + /** * @brief Loads a deck from a local file. * @param fileName The file to load diff --git a/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.cpp b/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.cpp index 98f5a306b..1c38214bd 100644 --- a/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.cpp +++ b/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.cpp @@ -53,6 +53,16 @@ void ColorIdentityWidget::populateManaSymbolWidgets() } } +void ColorIdentityWidget::setColorIdentity(const QString &_colorIdentity) +{ + if (colorIdentity == _colorIdentity) { + return; + } + + colorIdentity = _colorIdentity; + populateManaSymbolWidgets(); +} + void ColorIdentityWidget::toggleUnusedVisibility() { populateManaSymbolWidgets(); diff --git a/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.h b/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.h index d9746b956..6512ba890 100644 --- a/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.h +++ b/cockatrice/src/interface/widgets/cards/additional_info/color_identity_widget.h @@ -23,6 +23,7 @@ public: static QStringList parseColorIdentity(const QString &manaString); public slots: + void setColorIdentity(const QString &_colorIdentity); void resizeEvent(QResizeEvent *event) override; void toggleUnusedVisibility(); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h index 74ea1cbdf..bfd0a170d 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h @@ -21,7 +21,7 @@ class DeckPreviewDeckTagsDisplayWidget : public QWidget FlowWidget *flowWidget; public: - explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, const QStringList &_tags); + explicit DeckPreviewDeckTagsDisplayWidget(QWidget *_parent, const QStringList &_tags = {}); void setTags(const QStringList &_tags); void refreshTags(); diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp index a9c1f0933..a2adb732c 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp @@ -71,21 +71,48 @@ void DeckPreviewWidget::resizeEvent(QResizeEvent *event) } } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +void DeckPreviewWidget::enterEvent(QEnterEvent *event) +#else +void DeckPreviewWidget::enterEvent(QEvent *event) +#endif +{ + QWidget::enterEvent(event); + reloadIfModified(); +} + +/** + * @brief Sets the lastModifiedTime to the value given by the file. + */ +void DeckPreviewWidget::updateLastModifiedTime() +{ + QFileInfo fileInfo(filePath); + lastModifiedTime = fileInfo.lastModified(); +} + +/** + * @brief Writes the current contents of the deck to file. Updates the lastModifiedTime afterward. + */ +void DeckPreviewWidget::writeDeckToFile() +{ + DeckLoader::saveToFile(deckLoader->getDeck()); + updateLastModifiedTime(); +} + void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess) { if (!deckLoadSuccess) { return; } - auto bannerCard = deckLoader->getDeck().deckList.getBannerCard().name.isEmpty() - ? ExactCard() - : CardDatabaseManager::query()->getCard(deckLoader->getDeck().deckList.getBannerCard()); - bannerCardDisplayWidget->setCard(bannerCard); + QFileInfo fileInfo(filePath); + lastModifiedTime = fileInfo.lastModified(); + bannerCardDisplayWidget->setFontSize(24); setFilePath(deckLoader->getDeck().lastLoadInfo.fileName); - colorIdentityWidget = new ColorIdentityWidget(this, getColorIdentity()); - deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckLoader->getDeck().deckList.getTags()); + colorIdentityWidget = new ColorIdentityWidget(this); + deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this); connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, this, &DeckPreviewWidget::setTags); bannerCardLabel = new QLabel(this); @@ -93,13 +120,11 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess) bannerCardComboBox = new QComboBox(this); bannerCardComboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); bannerCardComboBox->setObjectName("bannerCardComboBox"); - bannerCardComboBox->setCurrentText(deckLoader->getDeck().deckList.getBannerCard().name); bannerCardComboBox->installEventFilter(new NoScrollFilter(bannerCardComboBox)); connect(bannerCardComboBox, QOverload::of(&QComboBox::currentIndexChanged), this, &DeckPreviewWidget::setBannerCard); updateColorIdentityVisibility(SettingsCache::instance().getVisualDeckStorageShowColorIdentity()); - updateBannerCardComboBox(); updateBannerCardComboBoxVisibility(SettingsCache::instance().getVisualDeckStorageShowBannerCardComboBox()); updateTagsVisibility(SettingsCache::instance().getVisualDeckStorageShowTagsOnDeckPreviews()); @@ -108,9 +133,44 @@ void DeckPreviewWidget::initializeUi(const bool deckLoadSuccess) layout->addWidget(bannerCardLabel); layout->addWidget(bannerCardComboBox); - refreshBannerCardText(); - retranslateUi(); + resyncWidgets(); +} + +/** + * @brief Syncs the contents of the child widgets with the current deck. + */ +void DeckPreviewWidget::resyncWidgets() +{ + auto bannerCardRef = deckLoader->getDeck().deckList.getBannerCard(); + auto bannerCard = bannerCardRef.name.isEmpty() ? ExactCard() : CardDatabaseManager::query()->getCard(bannerCardRef); + + bannerCardDisplayWidget->setCard(bannerCard); + refreshBannerCardText(); + updateBannerCardComboBox(bannerCardRef.name); + colorIdentityWidget->setColorIdentity(getColorIdentity()); + deckTagsDisplayWidget->setTags(deckLoader->getDeck().deckList.getTags()); +} + +/** + * @brief Reloads the deck if the file's last modified time has increased since we last checked. + */ +void DeckPreviewWidget::reloadIfModified() +{ + QFileInfo fileInfo(filePath); + QDateTime newLastModifiedTime = fileInfo.lastModified(); + + if (!newLastModifiedTime.isValid() || newLastModifiedTime <= lastModifiedTime) { + return; + } + + bool success = deckLoader->reload(); + + if (success) { + fileInfo.refresh(); + lastModifiedTime = fileInfo.lastModified(); + resyncWidgets(); + } } void DeckPreviewWidget::updateVisibility() @@ -232,11 +292,8 @@ void DeckPreviewWidget::refreshBannerCardToolTip() } } -void DeckPreviewWidget::updateBannerCardComboBox() +void DeckPreviewWidget::updateBannerCardComboBox(const QString ¤tText) { - // Store the current text of the combo box - QString currentText = bannerCardComboBox->currentText(); - // Block signals temporarily bool wasBlocked = bannerCardComboBox->blockSignals(true); bannerCardComboBox->setUpdatesEnabled(false); @@ -300,7 +357,7 @@ void DeckPreviewWidget::setBannerCard(int /* changedIndex */) auto [name, id] = bannerCardComboBox->currentData().value>(); CardRef cardRef = {name, id}; deckLoader->getDeck().deckList.setBannerCard(cardRef); - DeckLoader::saveToFile(deckLoader->getDeck()); + writeDeckToFile(); bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef)); } @@ -323,7 +380,7 @@ void DeckPreviewWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewC void DeckPreviewWidget::setTags(const QStringList &tags) { deckLoader->getDeck().deckList.setTags(tags); - DeckLoader::saveToFile(deckLoader->getDeck()); + writeDeckToFile(); } QMenu *DeckPreviewWidget::createRightClickMenu() @@ -398,7 +455,7 @@ void DeckPreviewWidget::actRenameDeck() // write change deckLoader->getDeck().deckList.setName(newName); - DeckLoader::saveToFile(deckLoader->getDeck()); + writeDeckToFile(); // update VDS refreshBannerCardText(); @@ -429,9 +486,10 @@ void DeckPreviewWidget::actRenameFile() } deckLoader->getDeck().lastLoadInfo.fileName = newFilePath; + setFilePath(newFilePath); // update VDS - setFilePath(newFilePath); + updateLastModifiedTime(); refreshBannerCardText(); } diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h index 1dc67d158..98116cabe 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.h @@ -38,6 +38,7 @@ public: VisualDeckStorageWidget *visualDeckStorageWidget; QVBoxLayout *layout; QString filePath; + QDateTime lastModifiedTime; DeckLoader *deckLoader; DeckPreviewCardPictureWidget *bannerCardDisplayWidget = nullptr; ColorIdentityWidget *colorIdentityWidget = nullptr; @@ -57,18 +58,29 @@ public slots: void setFilePath(const QString &filePath); void refreshBannerCardText(); void refreshBannerCardToolTip(); - void updateBannerCardComboBox(); + void updateBannerCardComboBox(const QString ¤tText); void setBannerCard(int); void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance); void initializeUi(bool deckLoadSuccess); + void resyncWidgets(); + void reloadIfModified(); void updateVisibility(); void updateColorIdentityVisibility(bool visible); void updateBannerCardComboBoxVisibility(bool visible); void updateTagsVisibility(bool visible); void resizeEvent(QResizeEvent *event) override; +protected: +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + void enterEvent(QEnterEvent *event) override; // Qt6 signature +#else + void enterEvent(QEvent *event) override; // Qt5 signature +#endif + private: + void updateLastModifiedTime(); + void writeDeckToFile(); QMenu *createRightClickMenu(); void addSetBannerCardMenu(QMenu *menu);