29#include <wx/tokenzr.h>
49#define REGVERKEY wxString(wxT("/pluginregistryversion"))
50#define REGROOT wxString(wxT("/pluginregistry/"))
51#define REGCUSTOMPATHS wxString(wxT("/providercustompaths"))
54#define SETVERKEY wxString(wxT("/pluginsettingsversion"))
55#define SETVERCUR wxString(wxT("1.0"))
56#define SETROOT wxString(wxT("/pluginsettings/"))
58#define KEY_ID wxT("ID")
59#define KEY_PATH wxT("Path")
60#define KEY_SYMBOL wxT("Symbol")
61#define KEY_NAME wxT("Name")
62#define KEY_VENDOR wxT("Vendor")
63#define KEY_VERSION wxT("Version")
64#define KEY_DESCRIPTION wxT("Description")
65#define KEY_LASTUPDATED wxT("LastUpdated")
66#define KEY_ENABLED wxT("Enabled")
67#define KEY_VALID wxT("Valid")
68#define KEY_PROVIDERID wxT("ProviderID")
69#define KEY_EFFECTTYPE wxT("EffectType")
70#define KEY_EFFECTFAMILY wxT("EffectFamily")
71#define KEY_EFFECTDEFAULT wxT("EffectDefault")
72#define KEY_EFFECTINTERACTIVE wxT("EffectInteractive")
73#define KEY_EFFECTREALTIME wxT("EffectRealtime")
74#define KEY_EFFECTAUTOMATABLE wxT("EffectAutomatable")
75#define KEY_EFFECTTYPE_NONE wxT("None")
76#define KEY_EFFECTTYPE_ANALYZE wxT("Analyze")
77#define KEY_EFFECTTYPE_GENERATE wxT("Generate")
78#define KEY_EFFECTTYPE_PROCESS wxT("Process")
79#define KEY_EFFECTTYPE_TOOL wxT("Tool")
80#define KEY_EFFECTTYPE_HIDDEN wxT("Hidden")
81#define KEY_IMPORTERIDENT wxT("ImporterIdent")
83#define KEY_IMPORTEREXTENSIONS wxT("ImporterExtensions")
116 switch (
desc.GetPluginType() ) {
120 auto family =
desc.GetEffectFamily();
121 if ( family.empty() )
124 return wxT(
'/') + family +
wxT(
"/Enable");
140 if (
auto &descriptor = pair.second; descriptor.GetPath() == path) {
142 descriptor.SetSymbol(
143 { descriptor.GetSymbol().
Internal(), *pName });
226 paths.push_back(ff.GetFullPath());
231#if defined(__WXMAC__)
238 ff.AppendDir(
wxT(
"plug-ins"));
239 paths.push_back(ff.GetPath());
242 for (
const auto &filePath : pathList)
245 const wxString path{ ff.GetFullPath() };
246 if (paths.Index(path, wxFileName::IsCaseSensitive()) == wxNOT_FOUND)
248 paths.push_back(path);
253 for (
size_t i = 0, cnt = paths.size(); i < cnt; i++)
255 ff = paths[i] + wxFILE_SEP_PATH + pattern;
256 wxDir::GetAllFiles(ff.GetPath(), &files, ff.GetFullName(), directories ? wxDIR_DEFAULT : wxDIR_FILES);
350 auto &pluginDesc = it->second;
351 const auto pluginType = pluginDesc.GetPluginType();
358 if(!moduleManager.
CheckPluginExist(pluginDesc.GetProviderID(), pluginDesc.GetPath()))
401 mm.DiscoverProviders();
402 for (
auto& [
id, module] : mm.Providers()) {
405 module->AutoRegisterPlugins(*
this);
416 auto&
desc = p.second;
430 const wxFileName src{ fileName };
434 (mm.CreateProviderInstance(plug.GetID(), plug.GetPath()));
439 const auto &extensions = module->GetFileExtensions();
441 extensions.Index(src.GetExt(),
false) != wxNOT_FOUND ) {
445 module->DiscoverPluginsAtPath(fileName, errMsg, {});
455 dst.SetFullName( src.GetFullName() );
456 if ( dst.Exists() ) {
459 XO(
"Overwrite the plug-in file %s?")
460 .
Format( dst.GetFullPath() ),
463 .ButtonStyle(Button::YesNo)));
470 auto dstPath = dst.GetFullPath();
471 if ( src.FileExists() )
474 src.GetFullPath(), dstPath, true );
484 XO(
"Plug-in file is in use. Failed to overwrite") );
489 std::vector<PluginID> ids;
490 std::vector<wxString>
names;
491 nPlugIns = module->DiscoverPluginsAtPath(dstPath, errMsg,
499 names.push_back(
ident->GetSymbol().Translation() );
505 XO(
"Failed to register:\n%s").
Format( errMsg ) );
510 if (
auto nIds = ids.size()) {
514 "Enable this plug-in?\n",
515 "Enable these plug-ins?\n",
525 .ButtonStyle(Button::YesNo)));
526 for (
const auto &
id : ids)
545 auto ®istry = *pRegistry;
549 if (!registry.HasGroup(
REGROOT))
569 wxString cfgPath =
REGROOT + group + wxCONFIG_PATH_SEPARATOR;
570 wxArrayString groupsToDelete;
572 auto cfgGroup = registry.BeginGroup(cfgPath);
573 for(
const auto& groupName : registry.GetChildGroups())
575 auto effectGroup = registry.BeginGroup(groupName);
576 wxString effectSymbol = registry.Read(
KEY_SYMBOL,
"");
577 wxString effectVersion = registry.Read(
KEY_VERSION,
"");
589 }
else if ((effectSymbol ==
"Sample Data Export") && (effectVersion ==
"n/a")) {
590 groupsToDelete.push_back(cfgPath + groupName);
592 }
else if ((effectSymbol ==
"Sample Data Import") && (effectVersion ==
"n/a")) {
593 groupsToDelete.push_back(cfgPath + groupName);
599 for (
unsigned int i = 0; i < groupsToDelete.size(); i++) {
600 registry.DeleteGroup(groupsToDelete[i]);
627 const auto fullExePath =
631 wxFileName exeFn{ fullExePath };
633 exeFn.SetName(wxString{});
634 while(exeFn.GetDirCount() && !exeFn.GetDirs().back().EndsWith(
".app"))
635 exeFn.RemoveLastDir();
637 const auto goodPath = exeFn.GetPath();
639 if(exeFn.GetDirCount())
640 exeFn.RemoveLastDir();
641 const auto possiblyBadPath = exeFn.GetPath();
643 auto AcceptPath = [&](
const wxString &path) {
644 if (!path.StartsWith(possiblyBadPath))
647 if (path.StartsWith(goodPath))
653 auto AcceptPath = [](
const wxString&){
return true; };
660 const auto cfgGroup = pRegistry->
BeginGroup(cfgPath);
664 const auto effectGroup = pRegistry->
BeginGroup(group);
673 plug.
SetID(groupName);
687 if (!AcceptPath(strVal))
835 wxStringTokenizer tkr(strVal,
wxT(
":"));
836 while (tkr.HasMoreTokens())
838 extensions.push_back(tkr.GetNextToken());
874 auto ®istry = *pRegistry;
918 const auto wxarr = wxSplit(paths,
';');
927 std::copy(paths.begin(), paths.end(), std::back_inserter(wxarr));
935 auto & plug = pair.second;
937 if (plug.GetPluginType() != type)
951 pRegistry->
Write(
KEY_NAME, plug.GetSymbol().Msgid().MSGID());
995 const auto & extensions = plug.GetImporterExtensions();
997 for (
size_t i = 0, cnt = extensions.size(); i < cnt; i++)
999 strExt += extensions[i] +
wxT(
":");
1001 strExt.RemoveLast(1);
1017 std::unique_ptr<EffectDefinitionInterface> effect,
PluginType type)
1035 return plug.
GetID();
1047 return pair.second.GetPluginType() == type; });
1053 return &iter->second;
1057 return plug.
GetID() == ID;
1073 if (!all && !(plug.IsValid() && plug.IsEnabled()))
1075 auto plugType = plug.GetPluginType();
1081 if (!(setting.empty() ||
gPrefs->
Read( setting,
true )))
1099, mPluginType{ type }
1107, mEffectType{ type }
1123 return iter->second.IsEnabled();
1131 iter->second.SetEnabled(enable);
1142 return iter->second.GetSymbol();
1160 if (strTarget.
empty())
1170 auto& ID = plug.GetID();
1180 return it->second.get();
1184 auto&
desc = it->second;
1192 auto result = pluginInterface.get();
1206 const auto&
desc = it->second;
1207 const auto type =
desc.GetPluginType();
1223 provider->AutoRegisterPlugins(*
this);
1237 wxArrayString pathIndex;
1239 auto &plug = pair.second;
1243 pathIndex.push_back(plug.GetPath().BeforeFirst(
wxT(
';')));
1256 std::map<wxString, std::vector<wxString>> newPaths;
1257 for(
auto& [
id, provider] : moduleManager.Providers())
1259 const auto paths = provider->FindModulePaths(*
this);
1260 for(
const auto& path : paths)
1262 const auto modulePath = path.BeforeFirst(
';');
1265 return plug.
GetPath().BeforeFirst(
wxT(
';')) == modulePath;
1269 newPaths[modulePath].push_back(
id);
1284 return wxString::Format(
wxT(
"%s_%s_%s_%s_%s"),
1294 return wxString::Format(
wxT(
"%s_%s_%s_%s_%s"),
1315 auto strings = wxSplit(ID,
'_');
1316 if (strings.size() == 5)
1331 str =
wxT(
"Placeholder");
1361 if (provider ==
nullptr)
1363 wxLogWarning(
"Unable to find a provider for '%s'", providerID);
1367 if (provider->CheckPluginExist(plug.
GetPath()) ==
false)
1369 wxLogWarning(
"Plugin '%s' does not exist", plug.
GetID());
1431 auto group =
settings->BeginGroup(groupName);
1432 return !
settings->GetChildGroups().empty() || !
settings->GetChildKeys().empty();
1437 if (groupName.empty() || !
HasGroup(groupName))
1444 subgroups.push_back(
name);
1454template<
typename T>
class TD;
1462 const auto visitor = [&](
const auto var){
1463 const auto pVar = &var.get();
1465 using Type =
typename decltype(var)::type;
1466 const auto pDefval =
1467 std::get_if<std::reference_wrapper<const Type>>(&defval);
1472 return Visit(visitor, var);
1481 const auto visitor = [&](
const auto value){
1484 return Visit(visitor, value);
1513 wxCONFIG_PATH_SEPARATOR +
1514 (shared ?
wxT(
"shared") :
wxT(
"private")) +
1515 wxCONFIG_PATH_SEPARATOR;
1525 wxFileName ff(group);
1526 if (!ff.GetName().empty())
1528 path += ff.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
1538 auto path =
Group(type, ID, group);
1551 if (ID.StartsWith(
wxT(
"base64:")))
1553 wxString
id = ID.Mid(7);
1555 id = wxString::FromUTF8(buf.get(),
Base64::Decode(
id, buf.get()));
1559 const wxCharBuffer & buf = ID.ToUTF8();
@ Internal
Indicates internal failure from Audacity.
Toolkit-neutral facade for basic user interface services.
std::vector< PluginPath > PluginPaths
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
std::vector< RegistryPath > RegistryPaths
#define XPC(sing, plur, n, c)
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
static CommandHandlerObject & ident(AudacityProject &project)
@ PluginTypeAudacityCommand
bool Regver_lt(const PluginRegistryVersion ®ver1, const PluginRegistryVersion ®ver2)
bool Regver_le(const PluginRegistryVersion ®ver1, const PluginRegistryVersion ®ver2)
wxString PluginRegistryVersion
Type of plugin registry version information.
#define KEY_EFFECTAUTOMATABLE
#define KEY_IMPORTEREXTENSIONS
#define KEY_EFFECTTYPE_TOOL
#define KEY_IMPORTERIDENT
static PluginManager::ConfigFactory sFactory
#define KEY_EFFECTTYPE_GENERATE
#define KEY_EFFECTTYPE_PROCESS
#define KEY_EFFECTINTERACTIVE
#define KEY_EFFECTTYPE_HIDDEN
#define KEY_EFFECTREALTIME
#define KEY_EFFECTTYPE_NONE
#define KEY_EFFECTTYPE_ANALYZE
#define KEY_EFFECTDEFAULT
#define NYQUIST_PROMPT_ID
Generalized interface for discovery of plug-ins for one protocol.
audacity::BasicSettings * gPrefs
static const AttachedProjectObjects::RegisteredFactory manager
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
emulates std::visit for one visitor
ComponentInterface provides name / vendor / version functions to identify plugins....
virtual PluginPath GetPath() const =0
virtual VendorSymbol GetVendor() const =0
TranslatableString GetName() const
virtual ComponentInterfaceSymbol GetSymbol() const =0
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const wxString & Internal() const
const TranslatableString & Msgid() const
EffectDefinitionInterface is a ComponentInterface that adds some basic read-only information about ef...
virtual EffectType GetClassification() const
Determines which menu it appears in; default same as GetType().
virtual bool IsDefault() const =0
Whether the effect sorts "above the line" in the menus.
virtual bool IsInteractive() const =0
Whether the effect needs a dialog for entry of settings.
static Identifier GetSquashedName(const Identifier &ident)
A utility that strips spaces and CamelCases a name.
virtual bool SupportsAutomation() const =0
Whether the effect has any automatable controls.
virtual RealtimeSince RealtimeSupport() const =0
Since which version of Audacity has the effect supported realtime?
virtual EffectFamilySymbol GetFamily() const =0
Report identifier and user-visible name of the effect protocol.
An explicitly nonlocalized string, not meant for the user to see.
static ModuleManager & Get()
static wxString GetPluginTypeString()
static PluginID GetID(const PluginProvider *provider)
PluginProvider * CreateProviderInstance(const PluginID &provider, const PluginPath &path)
bool CheckPluginExist(const PluginID &providerId, const PluginPath &path)
CallbackReturn Publish(const PluginsChangedMessage &message)
Send a message to connected callbacks.
void SetEnabled(bool enable)
void SetEffectLegacy(bool legacy)
void SetImporterExtensions(FileExtensions extensions)
const ComponentInterfaceSymbol & GetSymbol() const
PluginType GetPluginType() const
void SetVendor(const wxString &vendor)
void SetImporterIdentifier(const wxString &identifier)
wxString GetEffectFamily() const
void SetPath(const PluginPath &path)
void SetValid(bool valid)
const wxString & GetID() const
const wxString & GetVendor() const
void SetSymbol(const ComponentInterfaceSymbol &symbol)
void SetProviderID(const PluginID &providerID)
const PluginPath & GetPath() const
void SetID(const PluginID &ID)
void SetEffectType(EffectType type)
void SetEffectFamily(const wxString &family)
void SetPluginType(PluginType type)
const wxString & GetProviderID() const
void SetEffectAutomatable(bool automatable)
void SetEffectDefault(bool dflt)
void SetEffectInteractive(bool interactive)
void SetRealtimeSupport(EffectDefinitionInterface::RealtimeSince realtime)
void SetVersion(const wxString &version)
void DeserializeRealtimeSupport(const wxString &value)
for deserialization
void Advance(bool incrementing)
Iterator(PluginManager &manager)
Iterates all, even disabled.
const PluginManager & mPm
PluginMap::iterator mIterator
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
static PluginID OldGetID(const EffectDefinitionInterface *effect)
bool GetConfigSubgroups(ConfigurationType type, const PluginID &ID, const RegistryPath &group, RegistryPaths &subgroups) override
bool HasConfigGroup(ConfigurationType type, const PluginID &ID, const RegistryPath &group)
bool IsPluginEnabled(const PluginID &ID)
bool GetConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key, ConfigReference var, ConfigConstReference defval) override
std::vector< PluginDescriptor > mEffectPluginsCleared
void ClearEffectPlugins()
PluginRegistryVersion mRegver
static PluginID GetID(const PluginProvider *provider)
std::map< wxString, std::vector< wxString > > CheckPluginUpdates()
Ensures that all currently registered plugins still exist and scans for new ones.
bool IsPluginRegistered(const PluginPath &path, const TranslatableString *pSymbol) override
Was the plugin registry already populated for a path (maybe from loading the config file)?
bool IsPluginLoaded(const wxString &ID) const
void StoreCustomPaths(const PluginProvider &provider, const PluginPaths &paths) override
RegistryPath Group(ConfigurationType type, const PluginID &ID, const RegistryPath &group)
TranslatableString GetName(const PluginID &ID) const
bool HasConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
std::function< std::unique_ptr< audacity::BasicSettings >(const FilePath &localFilename) > ConfigFactory
void Save()
Save to preferences.
void UnregisterPlugin(const PluginID &ID)
void FindFilesInPathList(const wxString &pattern, const FilePaths &pathList, FilePaths &files, bool directories=false) override
bool GetSubgroups(const RegistryPath &group, RegistryPaths &subgroups)
static Identifier GetEffectNameFromID(const PluginID &ID)
bool HasGroup(const RegistryPath &group)
void LoadGroup(audacity::BasicSettings *pRegistry, PluginType type)
void Load()
Load from preferences.
Range PluginsOfType(int type)
PluginDescriptor & CreatePlugin(const PluginID &id, ComponentInterface *ident, PluginType type)
static bool IsPluginAvailable(const PluginDescriptor &plug)
const PluginRegistryVersion & GetRegistryVersion() const override
RegistryPath Key(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key)
static std::unique_ptr< PluginManager > mInstance
void Initialize(ConfigFactory factory)
RegistryPath GetPluginEnabledSetting(const PluginID &ID) const
PluginPaths ReadCustomPaths(const PluginProvider &provider) override
bool DropFile(const wxString &fileName)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
void EnablePlugin(const PluginID &ID, bool enable)
const PluginID & GetByCommandIdentifier(const CommandID &strTarget)
void RegisterPlugin(PluginDescriptor &&desc)
bool RemoveConfig(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
audacity::BasicSettings * GetSettings()
void SaveGroup(audacity::BasicSettings *pRegistry, PluginType type)
CommandID GetCommandIdentifier(const PluginID &ID) const
PluginMap mRegisteredPlugins
const ComponentInterfaceSymbol & GetSymbol(const PluginID &ID) const
wxString ConvertID(const PluginID &ID)
std::unique_ptr< audacity::BasicSettings > mSettings
RegistryPath SettingsPath(ConfigurationType type, const PluginID &ID)
bool SetConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key, ConfigConstReference value) override
int GetPluginCount(PluginType type)
static wxString GetPluginTypeString(PluginType type)
void NotifyPluginsChanged()
bool RemoveConfigSubgroup(ConfigurationType type, const PluginID &ID, const RegistryPath &group) override
std::map< PluginID, std::unique_ptr< ComponentInterface > > mLoadedInterfaces
static PluginManager & Get()
static const PluginID & AudacityCommandRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
PluginSettings::ConfigReference ConfigReference
static const PluginID & DefaultRegistrationCallback(PluginProvider *provider, ComponentInterface *ident)
PluginSettings::ConfigConstReference ConfigConstReference
virtual EffectFamilySymbol GetOptionalFamilySymbol()=0
A symbol identifying the family of plug-ins provided by this.
virtual std::unique_ptr< ComponentInterface > LoadPlugin(const PluginPath &path)=0
Load the plug-in at a path reported by DiscoverPluginsAtPath.
virtual FilePath InstallPath()=0
Where plug-in files should be copied to install them.
Holds a msgid for the translation catalog; may also bind format arguments.
Base class for objects that provide facility to store data persistently, and access it with string ke...
virtual bool Flush() noexcept=0
virtual bool Exists(const wxString &key) const
Returns true if group or entry exists.
GroupScope BeginGroup(const wxString &prefix)
Appends a prefix to the current group or sets a new absolute path. Group that was set as current befo...
bool DeleteGroup(const wxString &key)
Deletes specified group if exists.
virtual bool Write(const wxString &key, bool value)=0
bool DeleteEntry(const wxString &key)
Deletes specified entry if exists.
virtual bool Read(const wxString &key, bool *value) const =0
virtual wxArrayString GetChildGroups() const =0
Returns all child groups within the current group.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
STRINGS_API wxString Encode(const void *in, int len)
STRINGS_API int Decode(const wxString &in, void *out)
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
FILES_API FilePath PlugInDir()
The user plug-in directory (not a system one)
FILES_API bool DoCopyFile(const FilePath &file1, const FilePath &file2, bool overwrite=true)
FILES_API FilePath PluginRegistry()
FILES_API FilePath PluginSettings()
const TranslatableString desc
const char * end(const char *str) noexcept
const char * begin(const char *str) noexcept
void copy(const T *src, T *dst, int32_t n)
MessageBoxOptions && Caption(TranslatableString caption_) &&