diff --git a/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp b/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp index a78b173ade..6925c7bad2 100644 --- a/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp +++ b/doomsday/apps/client/src/ui/home/packagescolumnwidget.cpp @@ -25,10 +25,12 @@ #include #include #include +#include #include #include #include +#include using namespace de; @@ -52,10 +54,12 @@ static PopupWidget *makePackageFoldersDialog() } DENG_GUI_PIMPL(PackagesColumnWidget) +, DENG2_OBSERVES(Games, Readiness) { PackagesWidget *packages; LabelWidget *countLabel; ui::ListData actions; + LoopCallback mainCall; Instance(Public *i) : Base(i) { @@ -105,6 +109,14 @@ DENG_GUI_PIMPL(PackagesColumnWidget) return menu; }, ui::Down); } + + void gameReadinessUpdated() override + { + if (mainCall.isEmpty()) + { + mainCall.enqueue([this] () { packages->refreshPackages(); }); + } + } }; PackagesColumnWidget::PackagesColumnWidget() @@ -130,7 +142,8 @@ PackagesColumnWidget::PackagesColumnWidget() d->packages->rule().height()); d->packages->setFilterEditorMinimumY(scrollArea().margins().top()); - d->packages->refreshPackages(); + + DoomsdayApp::games().audienceForReadiness() += d; } String PackagesColumnWidget::tabHeading() const diff --git a/doomsday/apps/client/src/ui/widgets/packageswidget.cpp b/doomsday/apps/client/src/ui/widgets/packageswidget.cpp index 0e66694141..95eabcee32 100644 --- a/doomsday/apps/client/src/ui/widgets/packageswidget.cpp +++ b/doomsday/apps/client/src/ui/widgets/packageswidget.cpp @@ -59,7 +59,7 @@ static PackageLoadStatus isPackageLoaded; PackagesWidget::IPackageStatus::~IPackageStatus() {} DENG_GUI_PIMPL(PackagesWidget) -, DENG2_OBSERVES(res::Bundles, Refresh) +, DENG2_OBSERVES(res::Bundles, Identify) , public ChildWidgetOrganizer::IFilter , public ChildWidgetOrganizer::IWidgetFactory { @@ -484,14 +484,16 @@ DENG_GUI_PIMPL(PackagesWidget) } } - void dataBundlesRefreshed() + void dataBundlesIdentified(bool) override { // After bundles have been refreshed, make sure the list items are up to date. - mainCall.enqueue([this] () + if (mainCall.isEmpty()) { - App::fileSystem().refresh(); - self.populate(); - }); + mainCall.enqueue([this] () + { + self.populate(); + }); + } } //- ChildWidgetOrganizer::IFilter --------------------------------------------- @@ -551,7 +553,7 @@ PackagesWidget::PackagesWidget(String const &name) { rule().setInput(Rule::Height, d->search->rule().height() + d->menu->rule().height()); - DoomsdayApp::bundles().audienceForRefresh() += d; + DoomsdayApp::bundles().audienceForIdentify() += d; } void PackagesWidget::setFilterEditorMinimumY(Rule const &minY) @@ -710,5 +712,5 @@ void PackagesWidget::operator << (PersistentState const &fromState) void PackagesWidget::refreshPackages() { App::fileSystem().refresh(); - d->tasks.start([] () { DoomsdayApp::bundles().identify(); }); + DoomsdayApp::bundles().identify(); } diff --git a/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h b/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h index 9826a5078f..ce8ab0cd46 100644 --- a/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h +++ b/doomsday/apps/libdoomsday/include/doomsday/resource/bundles.h @@ -41,7 +41,7 @@ class LIBDOOMSDAY_PUBLIC Bundles typedef QList BlockElements; /// Notified when a data bundle refresh/identification has been made. - DENG2_DEFINE_AUDIENCE2(Refresh, void dataBundlesRefreshed()) + DENG2_DEFINE_AUDIENCE2(Identify, void dataBundlesIdentified(bool wereIdentified)) DENG2_ERROR(InvalidError); @@ -71,11 +71,13 @@ class LIBDOOMSDAY_PUBLIC Bundles * previous call of this method. Recognized data files are linked as * packages under the /sys/bundles folder. * - * @see res::DataBundle::identifyPackages() + * Calling this starts a background task where the identification is performed. + * The method returns immediately. The Identify audience is notified once the + * task is finished. * - * @return @c true, if one or more bundles were identified. + * @see res::DataBundle::identifyPackages() */ - bool identify(); + void identify(); /** * Finds a matching entry in the registry for a given data bundle. diff --git a/doomsday/apps/libdoomsday/src/doomsdayapp.cpp b/doomsday/apps/libdoomsday/src/doomsdayapp.cpp index 1ebbb2f589..deb92b9d99 100644 --- a/doomsday/apps/libdoomsday/src/doomsdayapp.cpp +++ b/doomsday/apps/libdoomsday/src/doomsdayapp.cpp @@ -308,16 +308,9 @@ DENG2_PIMPL(DoomsdayApp) packs.populate(); } - void folderPopulated(Folder &) + void folderPopulated(Folder &) // "/local/packs" or "/local/wads" { dataBundles.identify(); - mainCall.enqueue([this] () - { - if (initialized) - { - games.checkReadiness(); - } - }); } #ifdef UNIX @@ -404,23 +397,11 @@ void DoomsdayApp::initialize() void DoomsdayApp::initWadFolders() { d->initWadFolders(); - /*d->dataBundles.identify(); - - if (d->initialized) - { - games().checkReadiness(); - }*/ } void DoomsdayApp::initPackageFolders() { d->initPackageFolders(); - /*d->dataBundles.identify(); - - if (d->initialized) - { - games().checkReadiness(); - }*/ } void DoomsdayApp::determineGlobalPaths() diff --git a/doomsday/apps/libdoomsday/src/games.cpp b/doomsday/apps/libdoomsday/src/games.cpp index 21dd43af4f..5e86ee204d 100644 --- a/doomsday/apps/libdoomsday/src/games.cpp +++ b/doomsday/apps/libdoomsday/src/games.cpp @@ -24,18 +24,21 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include using namespace de; DENG2_PIMPL(Games) +, DENG2_OBSERVES(res::Bundles, Identify) { /// The actual collection. All games; @@ -45,6 +48,8 @@ DENG2_PIMPL(Games) QHash idLookup; // not owned, lower case + LoopCallback mainCall; + /** * Delegates game addition notifications to scripts. */ @@ -114,6 +119,14 @@ DENG2_PIMPL(Games) return nullptr; } + void dataBundlesIdentified(bool wereIdentified) + { + if (wereIdentified && mainCall.isEmpty()) + { + mainCall.enqueue([this] () { self.checkReadiness(); }); + } + } + DENG2_PIMPL_AUDIENCE(Addition) DENG2_PIMPL_AUDIENCE(Readiness) DENG2_PIMPL_AUDIENCE(Progress) diff --git a/doomsday/apps/libdoomsday/src/resource/bundles.cpp b/doomsday/apps/libdoomsday/src/resource/bundles.cpp index e02e54ccc6..812a561628 100644 --- a/doomsday/apps/libdoomsday/src/resource/bundles.cpp +++ b/doomsday/apps/libdoomsday/src/resource/bundles.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ DENG2_PIMPL(Bundles) QSet bundlesToIdentify; // lock for access LoopCallback mainCall; QHash formatEntries; + TaskPool tasks; Instance(Public *i) : Base(i) { @@ -149,10 +151,10 @@ DENG2_PIMPL(Bundles) } } - DENG2_PIMPL_AUDIENCE(Refresh) + DENG2_PIMPL_AUDIENCE(Identify) }; -DENG2_AUDIENCE_METHOD(Bundles, Refresh) +DENG2_AUDIENCE_METHOD(Bundles, Identify) Bundles::Bundles() : d(new Instance(this)) @@ -170,14 +172,16 @@ Bundles::BlockElements Bundles::formatEntries(DataBundle::Format format) const return d->formatEntries[format]; } -bool Bundles::identify() +void Bundles::identify() { - bool const identified = d->identifyAddedDataBundles(); - DENG2_FOR_AUDIENCE2(Refresh, i) + d->tasks.start([this] () { - i->dataBundlesRefreshed(); - } - return identified; + bool const identified = d->identifyAddedDataBundles(); + DENG2_FOR_AUDIENCE2(Identify, i) + { + i->dataBundlesIdentified(identified); + } + }); } Bundles::MatchResult Bundles::match(DataBundle const &bundle) const @@ -221,7 +225,7 @@ Bundles::MatchResult Bundles::match(DataBundle const &bundle) const String fileType = def->keyValue(QStringLiteral("fileType")); if (fileType.isEmpty()) fileType = "file"; // prefer files by default if ((!fileType.compareWithoutCase(QStringLiteral("file")) && source.status().type() == File::Status::FILE) || - (!fileType.compareWithoutCase(QStringLiteral("folder")) && source.status().type() == File::Status::FOLDER)) + (!fileType.compareWithoutCase(QStringLiteral("folder")) && source.status().type() == File::Status::FOLDER)) { ++score; } @@ -281,7 +285,7 @@ Bundles::MatchResult Bundles::match(DataBundle const &bundle) const } if (requiredSize >= 0 && - bundle.lumpDirectory()->lumpSize(lumpName) != duint32(requiredSize)) + bundle.lumpDirectory()->lumpSize(lumpName) != duint32(requiredSize)) { --score; break;