diff --git a/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp b/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp index 19366afb3d..a9209e7ff6 100644 --- a/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp +++ b/modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp @@ -99,7 +99,7 @@ namespace bool KnownPluginList::isListingUpToDate (const String& fileOrIdentifier) const { - if (getTypeForFile (fileOrIdentifier) == 0) + if (getTypeForFile (fileOrIdentifier) == nullptr) return false; for (int i = types.size(); --i >= 0;) @@ -121,8 +121,6 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, OwnedArray & typesFound, AudioPluginFormat& format) { - bool addedOne = false; - if (dontRescanIfAlreadyInList && getTypeForFile (fileOrIdentifier) != nullptr) { @@ -145,6 +143,9 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, return false; } + if (blacklist.contains (fileOrIdentifier)) + return false; + OwnedArray found; format.findAllTypesForFile (found, fileOrIdentifier); @@ -153,14 +154,11 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier, PluginDescription* const desc = found.getUnchecked(i); jassert (desc != nullptr); - if (addType (*desc)) - { - addedOne = true; - typesFound.add (new PluginDescription (*desc)); - } + addType (*desc); + typesFound.add (new PluginDescription (*desc)); } - return addedOne; + return found.size() > 0; } void KnownPluginList::scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& formatManager, @@ -196,10 +194,44 @@ void KnownPluginList::scanAndAddDragAndDroppedFiles (AudioPluginFormatManager& f } } +const StringArray& KnownPluginList::getBlacklistedFiles() const +{ + return blacklist; +} + +void KnownPluginList::addToBlacklist (const String& pluginID) +{ + if (! blacklist.contains (pluginID)) + { + blacklist.add (pluginID); + sendChangeMessage(); + } +} + +void KnownPluginList::removeFromBlacklist (const String& pluginID) +{ + const int index = blacklist.indexOf (pluginID); + + if (index >= 0) + { + blacklist.remove (index); + sendChangeMessage(); + } +} + +void KnownPluginList::clearBlacklistedFiles() +{ + if (blacklist.size() > 0) + { + blacklist.clear(); + sendChangeMessage(); + } +} + //============================================================================== struct PluginSorter { - PluginSorter (KnownPluginList::SortMethod method_) noexcept : method (method_) {} + PluginSorter (KnownPluginList::SortMethod sortMethod) noexcept : method (sortMethod) {} int compareElements (const PluginDescription* const first, const PluginDescription* const second) const @@ -248,12 +280,16 @@ XmlElement* KnownPluginList::createXml() const for (int i = 0; i < types.size(); ++i) e->addChildElement (types.getUnchecked(i)->createXml()); + for (int i = 0; i < blacklist.size(); ++i) + e->createNewChildElement ("BLACKLISTED")->setAttribute ("id", blacklist[i]); + return e; } void KnownPluginList::recreateFromXml (const XmlElement& xml) { clear(); + clearBlacklistedFiles(); if (xml.hasTagName ("KNOWNPLUGINS")) { @@ -261,7 +297,9 @@ void KnownPluginList::recreateFromXml (const XmlElement& xml) { PluginDescription info; - if (info.loadFromXml (*e)) + if (e->hasTagName ("BLACKLISTED")) + blacklist.add (e->getStringAttribute ("id")); + else if (info.loadFromXml (*e)) addType (info); } } diff --git a/modules/juce_audio_processors/scanning/juce_KnownPluginList.h b/modules/juce_audio_processors/scanning/juce_KnownPluginList.h index 9f655cd179..f4cbfd0907 100644 --- a/modules/juce_audio_processors/scanning/juce_KnownPluginList.h +++ b/modules/juce_audio_processors/scanning/juce_KnownPluginList.h @@ -113,6 +113,19 @@ public: const StringArray& filenames, OwnedArray & typesFound); + //============================================================================== + /** Returns the list of blacklisted files. */ + const StringArray& getBlacklistedFiles() const; + + /** Adds a plugin ID to the black-list. */ + void addToBlacklist (const String& pluginID); + + /** Removes a plugin ID from the black-list. */ + void removeFromBlacklist (const String& pluginID); + + /** Clears all the blacklisted files. */ + void clearBlacklistedFiles(); + //============================================================================== /** Sort methods used to change the order of the plugins in the list. */ @@ -169,6 +182,7 @@ public: private: //============================================================================== OwnedArray types; + StringArray blacklist; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList); }; diff --git a/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp b/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp index ecca4f08bc..d5f939a4be 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp +++ b/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp @@ -23,14 +23,22 @@ ============================================================================== */ +static StringArray readDeadMansPedalFile (const File& file) +{ + StringArray lines; + file.readLines (lines); + lines.removeEmptyStrings(); + return lines; +} + PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, AudioPluginFormat& formatToLookFor, FileSearchPath directoriesToSearch, const bool recursive, - const File& deadMansPedalFile_) + const File& deadMansPedal) : list (listToAddTo), format (formatToLookFor), - deadMansPedalFile (deadMansPedalFile_), + deadMansPedalFile (deadMansPedal), nextIndex (0), progress (0) { @@ -40,7 +48,7 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, // If any plugins have crashed recently when being loaded, move them to the // end of the list to give the others a chance to load correctly.. - const StringArray crashedPlugins (getDeadMansPedalFile()); + const StringArray crashedPlugins (readDeadMansPedalFile (deadMansPedalFile)); for (int i = 0; i < crashedPlugins.size(); ++i) { @@ -50,6 +58,8 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo, if (f == filesOrIdentifiersToScan[j]) filesOrIdentifiersToScan.move (j, -1); } + + applyBlacklistingsFromDeadMansPedal (listToAddTo, deadMansPedalFile); } PluginDirectoryScanner::~PluginDirectoryScanner() @@ -71,21 +81,18 @@ bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) OwnedArray typesFound; // Add this plugin to the end of the dead-man's pedal list in case it crashes... - StringArray crashedPlugins (getDeadMansPedalFile()); + StringArray crashedPlugins (readDeadMansPedalFile (deadMansPedalFile)); crashedPlugins.removeString (file); crashedPlugins.add (file); setDeadMansPedalFile (crashedPlugins); - list.scanAndAddFile (file, - dontRescanIfAlreadyInList, - typesFound, - format); + list.scanAndAddFile (file, dontRescanIfAlreadyInList, typesFound, format); // Managed to load without crashing, so remove it from the dead-man's-pedal.. crashedPlugins.removeString (file); setDeadMansPedalFile (crashedPlugins); - if (typesFound.size() == 0) + if (typesFound.size() == 0 && ! list.getBlacklistedFiles().contains (file)) failedFiles.add (file); } @@ -101,21 +108,18 @@ bool PluginDirectoryScanner::skipNextFile() return nextIndex < filesOrIdentifiersToScan.size(); } -StringArray PluginDirectoryScanner::getDeadMansPedalFile() +void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) { - StringArray lines; - if (deadMansPedalFile != File::nonexistent) - { - deadMansPedalFile.readLines (lines); - lines.removeEmptyStrings(); - } - - return lines; + deadMansPedalFile.replaceWithText (newContents.joinIntoString ("\n"), true, true); } -void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) +void PluginDirectoryScanner::applyBlacklistingsFromDeadMansPedal (KnownPluginList& list, const File& file) { - if (deadMansPedalFile != File::nonexistent) - deadMansPedalFile.replaceWithText (newContents.joinIntoString ("\n"), true, true); + // If any plugins have crashed recently when being loaded, move them to the + // end of the list to give the others a chance to load correctly.. + const StringArray crashedPlugins (readDeadMansPedalFile (file)); + + for (int i = 0; i < crashedPlugins.size(); ++i) + list.addToBlacklist (crashedPlugins[i]); } diff --git a/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h b/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h index 2c7e7c5edd..4b43a1938e 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h +++ b/modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h @@ -105,6 +105,10 @@ public: */ const StringArray& getFailedFiles() const noexcept { return failedFiles; } + /** Reads the given dead-mans-pedal file and applies its contents to the list. */ + static void applyBlacklistingsFromDeadMansPedal (KnownPluginList& listToApplyTo, + const File& deadMansPedalFile); + private: //============================================================================== KnownPluginList& list; @@ -115,7 +119,6 @@ private: int nextIndex; float progress; - StringArray getDeadMansPedalFile(); void setDeadMansPedalFile (const StringArray& newContents); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginDirectoryScanner); diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp index a8be5b40be..da55713522 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp @@ -43,6 +43,8 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager, setSize (400, 600); list.addChangeListener (this); updateList(); + + PluginDirectoryScanner::applyBlacklistingsFromDeadMansPedal (list, deadMansPedalFile); } PluginListComponent::~PluginListComponent() @@ -60,7 +62,7 @@ void PluginListComponent::resized() { listBox.setBounds (0, 0, getWidth(), getHeight() - 30); optionsButton.changeWidthToFitText (24); - optionsButton.setTopLeftPosition (8, getHeight() - 28); + optionsButton.setTopLeftPosition (0, getHeight() - 28); } void PluginListComponent::changeListenerCallback (ChangeBroadcaster*) @@ -76,7 +78,7 @@ void PluginListComponent::updateList() int PluginListComponent::getNumRows() { - return list.getNumTypes(); + return list.getNumTypes() + list.getBlacklistedFiles().size(); } void PluginListComponent::paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected) @@ -84,46 +86,60 @@ void PluginListComponent::paintListBoxItem (int row, Graphics& g, int width, int if (rowIsSelected) g.fillAll (findColour (TextEditor::highlightColourId)); - if (const PluginDescription* const pd = list.getType (row)) - { - GlyphArrangement ga; - ga.addCurtailedLineOfText (Font (height * 0.7f, Font::bold), pd->name, 8.0f, height * 0.8f, width - 10.0f, true); - - g.setColour (Colours::black); - ga.draw (g); + String name, desc; + bool isBlacklisted = false; - const Rectangle bb (ga.getBoundingBox (0, -1, false)); + if (row >= list.getNumTypes()) + { + isBlacklisted = true; + name = list.getBlacklistedFiles() [row - list.getNumTypes()]; + desc = TRANS("Deactivated after failing to initialise correctly"); + } + else if (const PluginDescription* const pd = list.getType (row)) + { + name = pd->name; - String desc; desc << pd->pluginFormatName << (pd->isInstrument ? " instrument" : " effect") - << " - " - << pd->numInputChannels << (pd->numInputChannels == 1 ? " in" : " ins") - << " / " - << pd->numOutputChannels << (pd->numOutputChannels == 1 ? " out" : " outs"); + << " - " << pd->numInputChannels << (pd->numInputChannels == 1 ? " in" : " ins") + << " / " << pd->numOutputChannels << (pd->numOutputChannels == 1 ? " out" : " outs"); - if (pd->manufacturerName.isNotEmpty()) - desc << " - " << pd->manufacturerName; + if (pd->manufacturerName.isNotEmpty()) desc << " - " << pd->manufacturerName; + if (pd->version.isNotEmpty()) desc << " - " << pd->version; + if (pd->category.isNotEmpty()) desc << " - category: '" << pd->category << '\''; + } - if (pd->version.isNotEmpty()) - desc << " - " << pd->version; + if (name.isNotEmpty()) + { + GlyphArrangement ga; + ga.addCurtailedLineOfText (Font (height * 0.7f, Font::bold), name, 8.0f, height * 0.8f, width - 10.0f, true); - if (pd->category.isNotEmpty()) - desc << " - category: '" << pd->category << '\''; + g.setColour (isBlacklisted ? Colours::red : Colours::black); + ga.draw (g); - g.setColour (Colours::grey); + const Rectangle bb (ga.getBoundingBox (0, -1, false)); ga.clear(); ga.addCurtailedLineOfText (Font (height * 0.6f), desc, - bb.getRight() + 10.0f, height * 0.8f, + jmax (bb.getRight() + 10.0f, width / 3.0f), height * 0.8f, width - bb.getRight() - 12.0f, true); + + g.setColour (isBlacklisted ? Colours::red : Colours::grey); ga.draw (g); } } +static void removePluginItem (KnownPluginList& list, int index) +{ + if (index < list.getNumTypes()) + list.removeType (index); + else + list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]); +} + void PluginListComponent::deleteKeyPressed (int lastRowSelected) { - list.removeType (lastRowSelected); + removePluginItem (list, lastRowSelected); } void PluginListComponent::removeSelected() @@ -132,15 +148,22 @@ void PluginListComponent::removeSelected() for (int i = list.getNumTypes(); --i >= 0;) if (selected.contains (i)) - list.removeType (i); + removePluginItem (list, i); } -void PluginListComponent::showSelectedFolder() +bool PluginListComponent::canShowSelectedFolder() const { - const PluginDescription* const desc = list.getType (listBox.getSelectedRow()); + if (const PluginDescription* const desc = list.getType (listBox.getSelectedRow())) + return File::createFileWithoutCheckingPath (desc->fileOrIdentifier).exists(); + + return false; +} - if (desc != nullptr && File (desc->fileOrIdentifier).existsAsFile()) - File (desc->fileOrIdentifier).getParentDirectory().startAsProcess(); +void PluginListComponent::showSelectedFolder() +{ + if (canShowSelectedFolder()) + if (const PluginDescription* const desc = list.getType (listBox.getSelectedRow())) + File (desc->fileOrIdentifier).getParentDirectory().startAsProcess(); } void PluginListComponent::removeMissingPlugins() @@ -180,7 +203,7 @@ void PluginListComponent::buttonClicked (Button* button) PopupMenu menu; menu.addItem (1, TRANS("Clear list")); menu.addItem (5, TRANS("Remove selected plugin from list"), listBox.getNumSelectedRows() > 0); - menu.addItem (6, TRANS("Show folder containing selected plugin"), listBox.getNumSelectedRows() > 0); + menu.addItem (6, TRANS("Show folder containing selected plugin"), canShowSelectedFolder()); menu.addItem (7, TRANS("Remove any plugins whose files no longer exist")); menu.addSeparator(); menu.addItem (2, TRANS("Sort alphabetically")); @@ -292,7 +315,7 @@ void PluginListComponent::scanFinished (const StringArray& failedFiles) StringArray shortNames; for (int i = 0; i < failedFiles.size(); ++i) - shortNames.add (File (failedFiles[i]).getFileName()); + shortNames.add (File::createFileWithoutCheckingPath (failedFiles[i]).getFileName()); currentScanner = nullptr; // mustn't delete this before using the failed files array diff --git a/modules/juce_audio_processors/scanning/juce_PluginListComponent.h b/modules/juce_audio_processors/scanning/juce_PluginListComponent.h index 5ec84a5b59..8bff5af371 100644 --- a/modules/juce_audio_processors/scanning/juce_PluginListComponent.h +++ b/modules/juce_audio_processors/scanning/juce_PluginListComponent.h @@ -97,6 +97,7 @@ private: void updateList(); void removeSelected(); void showSelectedFolder(); + bool canShowSelectedFolder() const; void removeMissingPlugins(); void buttonClicked (Button*);