@@ -36,6 +36,7 @@ static const char* pluginListKey() { return Settings::pluginListKey; }
3636/* noop. prevent OS error dialogs from child process */
3737static void pluginScannerCrashHandler (void *) {}
3838static File pluginsXmlFile () { return DataPath::applicationDataDir ().getChildFile (" plugins.xml" ); }
39+ static File pluginMetadataXmlFile () { return DataPath::applicationDataDir ().getChildFile (" plugin-metadata.xml" ); }
3940
4041static FileSearchPath readSearchPath (const PropertiesFile& props, const String& f)
4142{
@@ -638,6 +639,53 @@ class PluginManager::Private : public PluginScanner::Listener
638639 unverified.searchForPlugins (props);
639640 }
640641
642+ /* * Load hidden/favorite curation from a metadata file (keyed by
643+ PluginDescription::createIdentifierString()). */
644+ void loadPluginMetadata (const File& file)
645+ {
646+ hiddenPlugins.clearQuick ();
647+ favoritePlugins.clearQuick ();
648+
649+ auto xml = XmlDocument::parse (file);
650+ if (xml == nullptr || ! xml->hasTagName (types::PluginMetadata.toString ()))
651+ return ;
652+
653+ for (auto * const e : xml->getChildWithTagNameIterator (tags::plugin.toString ()))
654+ {
655+ const auto id = e->getStringAttribute (tags::identifier.toString ());
656+ if (id.isEmpty ())
657+ continue ;
658+ if (e->getBoolAttribute (tags::hidden.toString ()))
659+ hiddenPlugins.addIfNotAlreadyThere (id);
660+ if (e->getBoolAttribute (tags::favorite.toString ()))
661+ favoritePlugins.addIfNotAlreadyThere (id);
662+ }
663+ }
664+
665+ /* * Persist hidden/favorite curation. Only non-default entries are written. */
666+ void savePluginMetadata (const File& file)
667+ {
668+ XmlElement xml (types::PluginMetadata.toString ());
669+
670+ StringArray ids;
671+ ids.addArray (hiddenPlugins);
672+ ids.addArray (favoritePlugins);
673+ ids.removeDuplicates (false );
674+
675+ for (const auto & id : ids)
676+ {
677+ auto * const e = xml.createNewChildElement (tags::plugin.toString ());
678+ e->setAttribute (tags::identifier.toString (), id);
679+ if (hiddenPlugins.contains (id))
680+ e->setAttribute (tags::hidden.toString (), 1 );
681+ if (favoritePlugins.contains (id))
682+ e->setAttribute (tags::favorite.toString (), 1 );
683+ }
684+
685+ file.getParentDirectory ().createDirectory ();
686+ xml.writeTo (file);
687+ }
688+
641689 void getUnverifiedPlugins (const String& format, OwnedArray<PluginDescription>& plugs)
642690 {
643691 unverified.getPlugins (plugs, format, allPlugins);
@@ -648,6 +696,7 @@ class PluginManager::Private : public PluginScanner::Listener
648696 PluginManager& owner;
649697 AudioPluginFormatManager formats;
650698 KnownPluginList allPlugins;
699+ StringArray hiddenPlugins, favoritePlugins;
651700 File deadAudioPlugins;
652701 UnverifiedPlugins unverified;
653702 NodeFactory nodes;
@@ -951,6 +1000,7 @@ void PluginManager::restoreUserPlugins (const XmlElement& xml)
9511000 priv->allPlugins .recreateFromXml (xml);
9521001 scanInternalPlugins ();
9531002 priv->updateBlacklistedAudioPlugins ();
1003+ priv->loadPluginMetadata (detail::pluginMetadataXmlFile ());
9541004 if (props == nullptr )
9551005 return ;
9561006}
@@ -1119,4 +1169,58 @@ NodeProvider* PluginManager::getProvider (const String& format) noexcept
11191169 return nullptr ;
11201170}
11211171
1172+ // ==============================================================================
1173+ bool PluginManager::isPluginHidden (const PluginDescription& desc) const
1174+ {
1175+ return priv->hiddenPlugins .contains (desc.createIdentifierString ());
1176+ }
1177+
1178+ void PluginManager::setPluginHidden (const PluginDescription& desc, bool hidden)
1179+ {
1180+ const auto id = desc.createIdentifierString ();
1181+ if (hidden)
1182+ priv->hiddenPlugins .addIfNotAlreadyThere (id);
1183+ else
1184+ priv->hiddenPlugins .removeString (id);
1185+ priv->savePluginMetadata (detail::pluginMetadataXmlFile ());
1186+ priv->allPlugins .sendChangeMessage ();
1187+ }
1188+
1189+ bool PluginManager::isPluginFavorite (const PluginDescription& desc) const
1190+ {
1191+ return priv->favoritePlugins .contains (desc.createIdentifierString ());
1192+ }
1193+
1194+ void PluginManager::setPluginFavorite (const PluginDescription& desc, bool favorite)
1195+ {
1196+ const auto id = desc.createIdentifierString ();
1197+ if (favorite)
1198+ priv->favoritePlugins .addIfNotAlreadyThere (id);
1199+ else
1200+ priv->favoritePlugins .removeString (id);
1201+ priv->savePluginMetadata (detail::pluginMetadataXmlFile ());
1202+ priv->allPlugins .sendChangeMessage ();
1203+ }
1204+
1205+ Array<PluginDescription> PluginManager::getVisiblePluginTypes () const
1206+ {
1207+ Array<PluginDescription> result;
1208+ for (const auto & desc : priv->allPlugins .getTypes ())
1209+ if (! priv->hiddenPlugins .contains (desc.createIdentifierString ()))
1210+ result.add (desc);
1211+ return result;
1212+ }
1213+
1214+ Array<PluginDescription> PluginManager::getFavoritePluginTypes () const
1215+ {
1216+ Array<PluginDescription> result;
1217+ for (const auto & desc : priv->allPlugins .getTypes ())
1218+ {
1219+ const auto id = desc.createIdentifierString ();
1220+ if (priv->favoritePlugins .contains (id) && ! priv->hiddenPlugins .contains (id))
1221+ result.add (desc);
1222+ }
1223+ return result;
1224+ }
1225+
11221226} // namespace element
0 commit comments