From 86ad2a77a03f47b4b23495c96b3a625d7e71c97a Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 31 Aug 2022 17:06:25 +0100 Subject: [PATCH] FileTreeComponent: Avoid blocking the main thread when selecting items while scanning is in progress --- .../filebrowser/juce_FileTreeComponent.cpp | 69 ++++++++++++------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp index f5f1e6438c..916193cfd7 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp @@ -117,39 +117,30 @@ public: newList->addChangeListener (this); } - bool selectFile (const File& target) + void selectFile (const File& target) { if (file == target) { setSelected (true, true); - return true; + return; } - if (target.isAChildOf (file)) + if (subContentsList != nullptr && subContentsList->isStillLoading()) { - setOpen (true); - - for (int maxRetries = 500; --maxRetries > 0;) - { - for (int i = 0; i < getNumSubItems(); ++i) - if (auto* f = dynamic_cast (getSubItem (i))) - if (f->selectFile (target)) - return true; - - // if we've just opened and the contents are still loading, wait for it.. - if (subContentsList != nullptr && subContentsList->isStillLoading()) - { - Thread::sleep (10); - rebuildItemsFromContentList(); - } - else - { - break; - } - } + pendingFileSelection.emplace (*this, target); + return; } - return false; + pendingFileSelection.reset(); + + if (! target.isAChildOf (file)) + return; + + setOpen (true); + + for (int i = 0; i < getNumSubItems(); ++i) + if (auto* f = dynamic_cast (getSubItem (i))) + f->selectFile (target); } void changeListenerCallback (ChangeBroadcaster*) override @@ -224,6 +215,33 @@ public: const File file; private: + class PendingFileSelection : private Timer + { + public: + PendingFileSelection (FileListTreeItem& item, const File& f) + : owner (item), fileToSelect (f) + { + startTimer (10); + } + + ~PendingFileSelection() override + { + stopTimer(); + } + + private: + void timerCallback() override + { + // Take a copy of the file here, in case this PendingFileSelection + // object is destroyed during the call to selectFile. + owner.selectFile (File { fileToSelect }); + } + + FileListTreeItem& owner; + File fileToSelect; + }; + + Optional pendingFileSelection; FileTreeComponent& owner; DirectoryContentsList* parentContentsList; int indexInContentsList; @@ -316,8 +334,7 @@ void FileTreeComponent::setDragAndDropDescription (const String& description) void FileTreeComponent::setSelectedFile (const File& target) { if (auto* t = dynamic_cast (getRootItem())) - if (! t->selectFile (target)) - clearSelectedItems(); + t->selectFile (target); } void FileTreeComponent::setItemHeight (int newHeight)