@@ -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 <PluginDescription>& 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 <PluginDescription> 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); | |||
} | |||
} | |||
@@ -113,6 +113,19 @@ public: | |||
const StringArray& filenames, | |||
OwnedArray <PluginDescription>& 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 <PluginDescription> types; | |||
StringArray blacklist; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList); | |||
}; | |||
@@ -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 <PluginDescription> 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]); | |||
} |
@@ -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); | |||
@@ -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<float> 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<float> 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 | |||
@@ -97,6 +97,7 @@ private: | |||
void updateList(); | |||
void removeSelected(); | |||
void showSelectedFolder(); | |||
bool canShowSelectedFolder() const; | |||
void removeMissingPlugins(); | |||
void buttonClicked (Button*); | |||