| @@ -68,7 +68,7 @@ bool KnownPluginList::addType (const PluginDescription& type) | |||
| } | |||
| } | |||
| types.add (new PluginDescription (type)); | |||
| types.insert (0, new PluginDescription (type)); | |||
| sendChangeMessage(); | |||
| return true; | |||
| } | |||
| @@ -116,6 +116,11 @@ bool KnownPluginList::isListingUpToDate (const String& fileOrIdentifier) const | |||
| return true; | |||
| } | |||
| void KnownPluginList::setCustomScanner (CustomScanner* newScanner) | |||
| { | |||
| scanner = newScanner; | |||
| } | |||
| bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, | |||
| const bool dontRescanIfAlreadyInList, | |||
| OwnedArray <PluginDescription>& typesFound, | |||
| @@ -147,7 +152,11 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, | |||
| return false; | |||
| OwnedArray <PluginDescription> found; | |||
| format.findAllTypesForFile (found, fileOrIdentifier); | |||
| if (scanner != nullptr) | |||
| scanner->findPluginTypesFor (format, found, fileOrIdentifier); | |||
| else | |||
| format.findAllTypesForFile (found, fileOrIdentifier); | |||
| for (int i = 0; i < found.size(); ++i) | |||
| { | |||
| @@ -167,29 +176,39 @@ void KnownPluginList::scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& f | |||
| { | |||
| for (int i = 0; i < files.size(); ++i) | |||
| { | |||
| const String filenameOrID (files[i]); | |||
| bool found = false; | |||
| for (int j = 0; j < formatManager.getNumFormats(); ++j) | |||
| { | |||
| AudioPluginFormat* const format = formatManager.getFormat (j); | |||
| if (scanAndAddFile (files[i], true, typesFound, *format)) | |||
| return; | |||
| if (format->fileMightContainThisPluginType (filenameOrID) | |||
| && scanAndAddFile (filenameOrID, true, typesFound, *format)) | |||
| { | |||
| found = true; | |||
| break; | |||
| } | |||
| } | |||
| const File f (files[i]); | |||
| if (f.isDirectory()) | |||
| if (! found) | |||
| { | |||
| StringArray s; | |||
| const File f (filenameOrID); | |||
| if (f.isDirectory()) | |||
| { | |||
| Array<File> subFiles; | |||
| f.findChildFiles (subFiles, File::findFilesAndDirectories, false); | |||
| StringArray s; | |||
| for (int j = 0; j < subFiles.size(); ++j) | |||
| s.add (subFiles.getReference(j).getFullPathName()); | |||
| } | |||
| { | |||
| Array<File> subFiles; | |||
| f.findChildFiles (subFiles, File::findFilesAndDirectories, false); | |||
| for (int j = 0; j < subFiles.size(); ++j) | |||
| s.add (subFiles.getReference(j).getFullPathName()); | |||
| } | |||
| scanAndAddDragAndDroppedFiles (formatManager, s, typesFound); | |||
| scanAndAddDragAndDroppedFiles (formatManager, s, typesFound); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -485,3 +504,7 @@ int KnownPluginList::getIndexChosenByMenu (const int menuResultCode) const | |||
| const int i = menuResultCode - menuIdBase; | |||
| return isPositiveAndBelow (i, types.size()) ? i : -1; | |||
| } | |||
| //============================================================================== | |||
| KnownPluginList::CustomScanner::CustomScanner() {} | |||
| KnownPluginList::CustomScanner::~CustomScanner() {} | |||
| @@ -179,10 +179,25 @@ public: | |||
| /** Creates a PluginTree object containing all the known plugins. */ | |||
| PluginTree* createTree (const SortMethod sortMethod) const; | |||
| //============================================================================== | |||
| class CustomScanner | |||
| { | |||
| public: | |||
| CustomScanner(); | |||
| virtual ~CustomScanner(); | |||
| virtual void findPluginTypesFor (AudioPluginFormat& format, | |||
| OwnedArray <PluginDescription>& result, | |||
| const String& fileOrIdentifier) = 0; | |||
| }; | |||
| void setCustomScanner (CustomScanner* scanner); | |||
| private: | |||
| //============================================================================== | |||
| OwnedArray <PluginDescription> types; | |||
| StringArray blacklist; | |||
| ScopedPointer<CustomScanner> scanner; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList) | |||
| }; | |||
| @@ -31,7 +31,8 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, | |||
| list (listToEdit), | |||
| deadMansPedalFile (deadMansPedal), | |||
| optionsButton ("Options..."), | |||
| propertiesToUse (properties) | |||
| propertiesToUse (properties), | |||
| scanOnBackgroundThread (false) | |||
| { | |||
| listBox.setModel (this); | |||
| addAndMakeVisible (&listBox); | |||
| @@ -59,6 +60,11 @@ void PluginListComponent::setOptionsButtonText (const String& newText) | |||
| resized(); | |||
| } | |||
| void PluginListComponent::setScansOnMessageThread (bool useMessageThread) noexcept | |||
| { | |||
| scanOnBackgroundThread = ! useMessageThread; | |||
| } | |||
| void PluginListComponent::resized() | |||
| { | |||
| listBox.setBounds (0, 0, getWidth(), getHeight() - 30); | |||
| @@ -237,42 +243,79 @@ void PluginListComponent::filesDropped (const StringArray& files, int, int) | |||
| } | |||
| //============================================================================== | |||
| class PluginListComponent::Scanner : private Timer | |||
| class PluginListComponent::Scanner : private Timer, | |||
| private Thread | |||
| { | |||
| public: | |||
| Scanner (PluginListComponent& plc, AudioPluginFormat& format, const FileSearchPath& path) | |||
| : owner (plc), | |||
| Scanner (PluginListComponent& plc, | |||
| AudioPluginFormat& format, | |||
| const FileSearchPath& path, | |||
| bool useThread) | |||
| : Thread ("plugin_scan"), | |||
| owner (plc), | |||
| aw (TRANS("Scanning for plug-ins..."), | |||
| TRANS("Searching for all possible plug-in files..."), AlertWindow::NoIcon), | |||
| progress (0.0), | |||
| progress (0.0), finished (false), | |||
| scanner (owner.list, format, path, true, owner.deadMansPedalFile) | |||
| { | |||
| aw.addButton (TRANS("Cancel"), 0, KeyPress (KeyPress::escapeKey)); | |||
| aw.addProgressBarComponent (progress); | |||
| aw.enterModalState(); | |||
| if (useThread) | |||
| startThread(); | |||
| startTimer (20); | |||
| } | |||
| ~Scanner() | |||
| { | |||
| stopThread (10000); | |||
| } | |||
| private: | |||
| void timerCallback() | |||
| { | |||
| aw.setMessage (TRANS("Testing:\n\n") + scanner.getNextPluginFileThatWillBeScanned()); | |||
| if (scanner.scanNextFile (true) && aw.isCurrentlyModal()) | |||
| if (! isThreadRunning()) | |||
| { | |||
| progress = scanner.getProgress(); | |||
| startTimer (20); | |||
| if (doNextScan()) | |||
| startTimer (20); | |||
| } | |||
| if (! aw.isCurrentlyModal()) | |||
| finished = true; | |||
| if (finished) | |||
| owner.scanFinished (scanner.getFailedFiles()); | |||
| else | |||
| aw.setMessage (progressMessage); | |||
| } | |||
| void run() | |||
| { | |||
| while (doNextScan() && ! threadShouldExit()) | |||
| {} | |||
| } | |||
| bool doNextScan() | |||
| { | |||
| progressMessage = TRANS("Testing:\n\n") + scanner.getNextPluginFileThatWillBeScanned(); | |||
| if (scanner.scanNextFile (true)) | |||
| { | |||
| owner.scanFinished (scanner.getFailedFiles()); | |||
| progress = scanner.getProgress(); | |||
| return true; | |||
| } | |||
| finished = true; | |||
| return false; | |||
| } | |||
| PluginListComponent& owner; | |||
| AlertWindow aw; | |||
| String progressMessage; | |||
| double progress; | |||
| bool finished; | |||
| PluginDirectoryScanner scanner; | |||
| }; | |||
| @@ -312,7 +355,7 @@ void PluginListComponent::scanFor (AudioPluginFormat* format) | |||
| propertiesToUse->saveIfNeeded(); | |||
| } | |||
| currentScanner = new Scanner (*this, *format, path); | |||
| currentScanner = new Scanner (*this, *format, path, scanOnBackgroundThread); | |||
| } | |||
| } | |||
| @@ -61,6 +61,9 @@ public: | |||
| /** Changes the text in the panel's button. */ | |||
| void setOptionsButtonText (const String& newText); | |||
| /** Chooses whether to use the message thread or a background thread for scanning. */ | |||
| void setScansOnMessageThread (bool useMessageThread) noexcept; | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void resized(); | |||
| @@ -83,6 +86,7 @@ private: | |||
| ListBox listBox; | |||
| TextButton optionsButton; | |||
| PropertiesFile* propertiesToUse; | |||
| bool scanOnBackgroundThread; | |||
| class Scanner; | |||
| friend class Scanner; | |||