Audacity 3.2.0
PluginManager.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 PluginManager.cpp
6
7 Leland Lucius
8
9*******************************************************************/
22#include "PluginManager.h"
23
24
25
26#include <algorithm>
27
28#include <wx/log.h>
29#include <wx/tokenzr.h>
30
31#include "BasicUI.h"
32#include "PluginProvider.h"
33
34#include "Internat.h" // for macro XO
35#include "FileNames.h"
36#include "MemoryX.h"
37#include "ModuleManager.h"
39#include "Base64.h"
40
42//
43// PluginManager
44//
46
47// Registry has the list of plug ins
48#define REGVERKEY wxString(wxT("/pluginregistryversion"))
49#define REGROOT wxString(wxT("/pluginregistry/"))
50
51// Settings has the values of the plug in settings.
52#define SETVERKEY wxString(wxT("/pluginsettingsversion"))
53#define SETVERCUR wxString(wxT("1.0"))
54#define SETROOT wxString(wxT("/pluginsettings/"))
55
56#define KEY_ID wxT("ID")
57#define KEY_PATH wxT("Path")
58#define KEY_SYMBOL wxT("Symbol")
59#define KEY_NAME wxT("Name")
60#define KEY_VENDOR wxT("Vendor")
61#define KEY_VERSION wxT("Version")
62#define KEY_DESCRIPTION wxT("Description")
63#define KEY_LASTUPDATED wxT("LastUpdated")
64#define KEY_ENABLED wxT("Enabled")
65#define KEY_VALID wxT("Valid")
66#define KEY_PROVIDERID wxT("ProviderID")
67#define KEY_EFFECTTYPE wxT("EffectType")
68#define KEY_EFFECTFAMILY wxT("EffectFamily")
69#define KEY_EFFECTDEFAULT wxT("EffectDefault")
70#define KEY_EFFECTINTERACTIVE wxT("EffectInteractive")
71#define KEY_EFFECTREALTIME wxT("EffectRealtime")
72#define KEY_EFFECTAUTOMATABLE wxT("EffectAutomatable")
73#define KEY_EFFECTTYPE_NONE wxT("None")
74#define KEY_EFFECTTYPE_ANALYZE wxT("Analyze")
75#define KEY_EFFECTTYPE_GENERATE wxT("Generate")
76#define KEY_EFFECTTYPE_PROCESS wxT("Process")
77#define KEY_EFFECTTYPE_TOOL wxT("Tool")
78#define KEY_EFFECTTYPE_HIDDEN wxT("Hidden")
79#define KEY_IMPORTERIDENT wxT("ImporterIdent")
80//#define KEY_IMPORTERFILTER wxT("ImporterFilter")
81#define KEY_IMPORTEREXTENSIONS wxT("ImporterExtensions")
82
83// ============================================================================
84//
85// PluginManagerInterface implementation
86//
87// ============================================================================
88
90 PluginProvider *provider, ComponentInterface *pInterface )
91{
92 if(auto effectDefinitionInterface = dynamic_cast<EffectDefinitionInterface*>(pInterface))
93 return PluginManager::Get().RegisterPlugin(provider, effectDefinitionInterface, PluginTypeEffect);
94 return PluginManager::Get().RegisterPlugin(provider, pInterface);
95}
96
98 PluginProvider *provider, ComponentInterface *pInterface )
99{
100 return PluginManager::Get().RegisterPlugin(provider, pInterface);
101}
102
104{
105 auto pPlugin = GetPlugin( ID );
106 if ( pPlugin )
107 return GetPluginEnabledSetting( *pPlugin );
108 return {};
109}
110
112 const PluginDescriptor &desc ) const
113{
114 switch ( desc.GetPluginType() ) {
115 case PluginTypeModule: {
116 // Retrieve optional family symbol that was recorded in
117 // RegisterPlugin() for the module
118 auto family = desc.GetEffectFamily();
119 if ( family.empty() ) // as for built-in effect and command modules
120 return {};
121 else
122 return wxT('/') + family + wxT("/Enable");
123 }
124 case PluginTypeEffect:
125 // do NOT use GetEffectFamily() for this descriptor, but instead,
126 // delegate to the plugin descriptor of the provider, which may
127 // be different (may be empty)
128 return GetPluginEnabledSetting( desc.GetProviderID() );
129 default:
130 return {};
131 }
132}
133
135 const PluginPath &path, const TranslatableString *pName)
136{
137 for (auto &pair : mRegisteredPlugins) {
138 if (auto &descriptor = pair.second; descriptor.GetPath() == path) {
139 if (pName)
140 descriptor.SetSymbol(
141 { descriptor.GetSymbol().Internal(), *pName });
142 return true;
143 }
144 }
145 return false;
146}
147
148bool PluginManager::IsPluginLoaded(const wxString& ID) const
149{
150 return mLoadedInterfaces.find(ID) != mLoadedInterfaces.end();
151}
152
154{
155 mRegisteredPlugins[desc.GetID()] = std::move(desc);
156}
157
159{
160 PluginDescriptor & plug =
161 CreatePlugin(GetID(provider), provider, PluginTypeModule);
163
164 plug.SetEnabled(true);
165 plug.SetValid(true);
166
167 return plug.GetID();
168}
169
171 PluginProvider *provider, ComponentInterface *command)
172{
174
175 plug.SetProviderID(PluginManager::GetID(provider));
176
177 plug.SetEnabled(true);
178 plug.SetValid(true);
179
180 return plug.GetID();
181}
182
184 PluginProvider *provider, EffectDefinitionInterface *effect, int type)
185{
186 PluginDescriptor & plug = CreatePlugin(GetID(effect), effect, (PluginType)type);
187
188 plug.SetProviderID(PluginManager::GetID(provider));
189
190 plug.SetEffectType(effect->GetClassification());
191 plug.SetEffectFamily(effect->GetFamily().Internal());
192 plug.SetEffectInteractive(effect->IsInteractive());
193 plug.SetEffectDefault(effect->IsDefault());
194 plug.SetRealtimeSupport(effect->RealtimeSupport());
196
197 plug.SetEnabled(true);
198 plug.SetValid(true);
199
200 return plug.GetID();
201}
202
203void PluginManager::FindFilesInPathList(const wxString & pattern,
204 const FilePaths & pathList,
205 FilePaths & files,
206 bool directories)
207{
208
209 wxLogNull nolog;
210
211 // Why bother...
212 if (pattern.empty())
213 {
214 return;
215 }
216
217 // TODO: We REALLY need to figure out the "Audacity" plug-in path(s)
218
219 FilePaths paths;
220
221 // Add the "per-user" plug-ins directory
222 {
223 const wxFileName &ff = FileNames::PlugInDir();
224 paths.push_back(ff.GetFullPath());
225 }
226
227 // Add the "Audacity" plug-ins directory
229#if defined(__WXMAC__)
230 // Path ends for example in "Audacity.app/Contents/MacOSX"
231 //ff.RemoveLastDir();
232 //ff.RemoveLastDir();
233 // just remove the MacOSX part.
234 ff.RemoveLastDir();
235#endif
236 ff.AppendDir(wxT("plug-ins"));
237 paths.push_back(ff.GetPath());
238
239 // Weed out duplicates
240 for (const auto &filePath : pathList)
241 {
242 ff = filePath;
243 const wxString path{ ff.GetFullPath() };
244 if (paths.Index(path, wxFileName::IsCaseSensitive()) == wxNOT_FOUND)
245 {
246 paths.push_back(path);
247 }
248 }
249
250 // Find all matching files in each path
251 for (size_t i = 0, cnt = paths.size(); i < cnt; i++)
252 {
253 ff = paths[i] + wxFILE_SEP_PATH + pattern;
254 wxDir::GetAllFiles(ff.GetPath(), &files, ff.GetFullName(), directories ? wxDIR_DEFAULT : wxDIR_FILES);
255 }
256
257 return;
258}
259
261 const RegistryPath & group)
262{
263 return HasGroup(Group(type, ID, group));
264}
265
267 const PluginID & ID, const RegistryPath & group, RegistryPaths & subgroups)
268{
269 return GetSubgroups(Group(type, ID, group), subgroups);
270}
271
273 const RegistryPath & group, const RegistryPath & key)
274{
275 return HasConfigValue(Key(type, ID, group, key));
276}
277
279 const RegistryPath & group, const RegistryPath & key,
281{
282 return GetConfigValue(Key(type, ID, group, key), var, defval);
283}
284
286 const RegistryPath & group, const RegistryPath & key,
288{
289 return SetConfigValue(Key(type, ID, group, key), value);
290}
291
293 const PluginID & ID, const RegistryPath & group)
294{
295 bool result = GetSettings()->DeleteGroup(Group(type, ID, group));
296 if (result)
297 {
298 GetSettings()->Flush();
299 }
300
301 return result;
302}
303
305 const RegistryPath & group, const RegistryPath & key)
306{
307 bool result = GetSettings()->DeleteEntry(Key(type, ID, group, key));
308 if (result)
309 {
310 GetSettings()->Flush();
311 }
312
313 return result;
314}
315
316// ============================================================================
317//
318// PluginManager
319//
320// ============================================================================
321
322// The one and only PluginManager
323std::unique_ptr<PluginManager> PluginManager::mInstance{};
324
325// ----------------------------------------------------------------------------
326// Creation/Destruction
327// ----------------------------------------------------------------------------
328
330{
331 mSettings = NULL;
332}
333
335{
336 // Ensure termination (harmless if already done)
337 Terminate();
338}
339
341{
343
344 // Check all known plugins to ensure they are still valid.
345 for (auto &pair : mRegisteredPlugins) {
346 auto &plug = pair.second;
347 const wxString & plugPath = plug.GetPath();
348 PluginType plugType = plug.GetPluginType();
349
350 if (plugType != PluginTypeNone && plugType != PluginTypeStub && plugType != PluginTypeModule)
351 {
352 plug.SetValid(mm.IsPluginValid(plug.GetProviderID(), plugPath, true));
353 if (!plug.IsValid())
354 {
355 plug.SetEnabled(false);
356 }
357 }
358 }
359
360 Save();
361}
362
363// ----------------------------------------------------------------------------
364// PluginManager implementation
365// ----------------------------------------------------------------------------
366
368
369// ============================================================================
370//
371// Return reference to singleton
372//
373// (Thread-safe...no active threading during construction or after destruction)
374// ============================================================================
375
377{
378 if (!mInstance)
379 {
381 }
382
383 return *mInstance;
384}
385
387{
388 sFactory = move(factory);
389
390 // Always load the registry first
391 Load();
392
393 // And force load of setting to verify it's accessible
394 GetSettings();
395
396 auto &mm = ModuleManager::Get();
397 mm.DiscoverProviders();
398 for (const auto &[id, module] : mm.Providers()) {
399 RegisterPlugin(module.get());
400 // Allow the module to auto-register children
401 module->AutoRegisterPlugins(*this);
402 }
403
405}
406
408{
409 // Get rid of all non-module(effects?) plugins first
410 for(auto& p : mRegisteredPlugins)
411 {
412 auto& desc = p.second;
413 if(desc.GetPluginType() == PluginTypeEffect)
414 mLoadedInterfaces.erase(desc.GetID());
415 }
416
417 // Now get rid of others
418 mRegisteredPlugins.clear();
419 mLoadedInterfaces.clear();
420}
421
422bool PluginManager::DropFile(const wxString &fileName)
423{
424 using namespace BasicUI;
425 auto &mm = ModuleManager::Get();
426 const wxFileName src{ fileName };
427
428 for (auto &plug : PluginsOfType(PluginTypeModule)) {
429 auto module = static_cast<PluginProvider *>
430 (mm.CreateProviderInstance(plug.GetID(), plug.GetPath()));
431 if (! module)
432 continue;
433
434 const auto &ff = module->InstallPath();
435 const auto &extensions = module->GetFileExtensions();
436 if ( !ff.empty() &&
437 extensions.Index(src.GetExt(), false) != wxNOT_FOUND ) {
438 TranslatableString errMsg;
439 // Do dry-run test of the file format
440 unsigned nPlugIns =
441 module->DiscoverPluginsAtPath(fileName, errMsg, {});
442 if (nPlugIns) {
443 // File contents are good for this module, so check no others.
444 // All branches of this block return true, even in case of
445 // failure for other reasons, to signal that other drag-and-drop
446 // actions should not be tried.
447
448 // Find path to copy it
449 wxFileName dst;
450 dst.AssignDir( ff );
451 dst.SetFullName( src.GetFullName() );
452 if ( dst.Exists() ) {
453 // Query whether to overwrite
454 bool overwrite = (MessageBoxResult::Yes == ShowMessageBox(
455 XO("Overwrite the plug-in file %s?")
456 .Format( dst.GetFullPath() ),
458 .Caption(XO("Plug-in already exists"))
459 .ButtonStyle(Button::YesNo)));
460 if ( !overwrite )
461 return true;
462 }
463
464 // Move the file or subtree
465 bool copied = false;
466 auto dstPath = dst.GetFullPath();
467 if ( src.FileExists() )
468 // A simple one-file plug-in
469 copied = FileNames::DoCopyFile(
470 src.GetFullPath(), dstPath, true );
471 else {
472 // A sub-folder
473 // such as for some VST packages
474 // Recursive copy needed -- to do
475 return true;
476 }
477
478 if (!copied) {
480 XO("Plug-in file is in use. Failed to overwrite") );
481 return true;
482 }
483
484 // Register for real
485 std::vector<PluginID> ids;
486 std::vector<wxString> names;
487 nPlugIns = module->DiscoverPluginsAtPath(dstPath, errMsg,
489 -> const PluginID& {
490 // Register as by default, but also collecting the PluginIDs
491 // and names
493 provider, ident);
494 ids.push_back(id);
495 names.push_back( ident->GetSymbol().Translation() );
496 return id;
497 });
498 if ( ! nPlugIns ) {
499 // Unlikely after the dry run succeeded
501 XO("Failed to register:\n%s").Format( errMsg ) );
502 return true;
503 }
504
505 // Ask whether to enable the plug-ins
506 if (auto nIds = ids.size()) {
507 auto message = XPC(
508 /* i18n-hint A plug-in is an optional added program for a sound
509 effect, or generator, or analyzer */
510 "Enable this plug-in?\n",
511 "Enable these plug-ins?\n",
512 0,
513 "plug-ins"
514 )( nIds );
515 for (const auto &name : names)
516 message.Join( Verbatim( name ), wxT("\n") );
517 bool enable = (MessageBoxResult::Yes == ShowMessageBox(
518 message,
520 .Caption(XO("Enable new plug-ins"))
521 .ButtonStyle(Button::YesNo)));
522 for (const auto &id : ids)
523 mRegisteredPlugins[id].SetEnabled(enable);
524 // Make changes to enabled status persist:
525 this->Save();
526 }
527
528 return true;
529 }
530 }
531 }
532
533 return false;
534}
535
537{
538 // Create/Open the registry
539 auto pRegistry = sFactory(FileNames::PluginRegistry());
540 auto &registry = *pRegistry;
541
542 // If this group doesn't exist then we have something that's not a registry.
543 // We should probably warn the user, but it's pretty unlikely that this will happen.
544 if (!registry.HasGroup(REGROOT))
545 {
546 // Must start over
547 // This DeleteAll affects pluginregistry.cfg only, not audacity.cfg
548 // That is, the memory of on/off states of effect (and generator,
549 // analyzer, and tool) plug-ins
550 registry.DeleteAll();
551 registry.Flush();
552 return;
553 }
554
555 // Check for a registry version that we can understand
556 // TODO: Should also check for a registry file that is newer than
557 // what we can understand.
558 mRegver = registry.Read(REGVERKEY);
559 if (Regver_lt(mRegver, "1.1")) {
560 // Conversion code here, for when registry version changes.
561
562 // We iterate through the effects, possibly updating their info.
563 wxString groupName;
564 long groupIndex;
565 wxString group = GetPluginTypeString(PluginTypeEffect);
566 wxString cfgPath = REGROOT + group + wxCONFIG_PATH_SEPARATOR;
567 wxArrayString groupsToDelete;
568
569 registry.SetPath(cfgPath);
570 for (bool cont = registry.GetFirstGroup(groupName, groupIndex);
571 cont;
572 registry.SetPath(cfgPath),
573 cont = registry.GetNextGroup(groupName, groupIndex))
574 {
575 registry.SetPath(groupName);
576 wxString effectSymbol = registry.Read(KEY_SYMBOL, "");
577 wxString effectVersion = registry.Read(KEY_VERSION, "");
578
579
580 // For 2.3.0 the plugins we distribute have moved around.
581 // So we upped the registry version number to 1.1.
582 // These particular config edits were originally written to fix Bug 1914.
583 if (Regver_le(mRegver, "1.0")) {
584 // Nyquist prompt is a built-in that has moved to the tools menu.
585 if (effectSymbol == NYQUIST_PROMPT_ID) {
586 registry.Write(KEY_EFFECTTYPE, "Tool");
587 // Old version of SDE was in Analyze menu. Now it is in Tools.
588 // We don't want both the old and the new.
589 } else if ((effectSymbol == "Sample Data Export") && (effectVersion == "n/a")) {
590 groupsToDelete.push_back(cfgPath + groupName);
591 // Old version of SDI was in Generate menu. Now it is in Tools.
592 } else if ((effectSymbol == "Sample Data Import") && (effectVersion == "n/a")) {
593 groupsToDelete.push_back(cfgPath + groupName);
594 }
595 }
596
597 }
598 // Doing the deletion within the search loop risked skipping some items,
599 // hence the delayed delete.
600 for (unsigned int i = 0; i < groupsToDelete.size(); i++) {
601 registry.DeleteGroup(groupsToDelete[i]);
602 }
603 registry.SetPath("");
604 // Updates done. Make sure we read the updated data later.
605 registry.Flush();
606 }
607
608 // Load all provider plugins first
609 LoadGroup(&registry, PluginTypeModule);
610
611 // Now the rest
612 LoadGroup(&registry, PluginTypeEffect);
614 LoadGroup(&registry, PluginTypeExporter);
615 LoadGroup(&registry, PluginTypeImporter);
616
617 LoadGroup(&registry, PluginTypeStub);
618 return;
619}
620
622{
623#ifdef __WXMAC__
624 // Bug 1590: On Mac, we should purge the registry of Nyquist plug-ins
625 // bundled with other versions of Audacity, assuming both versions
626 // were properly installed in /Applications (or whatever it is called in
627 // your locale)
628
629 const auto fullExePath = PlatformCompatibility::GetExecutablePath();
630
631 // Strip rightmost path components up to *.app
632 wxFileName exeFn{ fullExePath };
633 exeFn.SetEmptyExt();
634 exeFn.SetName(wxString{});
635 while(exeFn.GetDirCount() && !exeFn.GetDirs().back().EndsWith(".app"))
636 exeFn.RemoveLastDir();
637
638 const auto goodPath = exeFn.GetPath();
639
640 if(exeFn.GetDirCount())
641 exeFn.RemoveLastDir();
642 const auto possiblyBadPath = exeFn.GetPath();
643
644 auto AcceptPath = [&](const wxString &path) {
645 if (!path.StartsWith(possiblyBadPath))
646 // Assume it's not under /Applications
647 return true;
648 if (path.StartsWith(goodPath))
649 // It's bundled with this executable
650 return true;
651 return false;
652 };
653#else
654 auto AcceptPath = [](const wxString&){ return true; };
655#endif
656
657 wxString strVal;
658 bool boolVal;
659 wxString groupName;
660 long groupIndex;
661 wxString group = GetPluginTypeString(type);
662 wxString cfgPath = REGROOT + group + wxCONFIG_PATH_SEPARATOR;
663
664 pRegistry->SetPath(cfgPath);
665 for (bool cont = pRegistry->GetFirstGroup(groupName, groupIndex);
666 cont;
667 pRegistry->SetPath(cfgPath),
668 cont = pRegistry->GetNextGroup(groupName, groupIndex))
669 {
670 PluginDescriptor plug;
671
672 pRegistry->SetPath(groupName);
673
674 groupName = ConvertID(groupName);
675
676 // Bypass group if the ID is already in use
677 if (mRegisteredPlugins.count(groupName))
678 continue;
679
680 // Set the ID and type
681 plug.SetID(groupName);
682 plug.SetPluginType(type);
683
684 // Get the provider ID and bypass group if not found
685 if (!pRegistry->Read(KEY_PROVIDERID, &strVal, wxEmptyString))
686 {
687 // Bypass group if the provider isn't valid
688 if (!strVal.empty() && !mRegisteredPlugins.count(strVal))
689 continue;
690 }
691 plug.SetProviderID(PluginID(strVal));
692
693 // Get the path (optional)
694 pRegistry->Read(KEY_PATH, &strVal, wxEmptyString);
695 if (!AcceptPath(strVal))
696 // Ignore the obsolete path in the config file, during session,
697 // but don't remove it from the file. Maybe you really want to
698 // switch back to the other version of Audacity and lose nothing.
699 continue;
700 plug.SetPath(strVal);
701
702 /*
703 // PRL: Ignore names written in configs before 2.3.0!
704 // use Internal string only! Let the present version of Audacity map
705 // that to a user-visible string.
706 // Get the name and bypass group if not found
707 if (!pRegistry->Read(KEY_NAME, &strVal))
708 {
709 continue;
710 }
711 plug.SetName(strVal);
712 */
713
714 // Get the symbol...Audacity 2.3.0 or later requires it
715 // bypass group if not found
716 // Note, KEY_SYMBOL started getting written to config files in 2.1.0.
717 // KEY_NAME (now ignored) was written before that, but only for VST
718 // effects.
719 if (!pRegistry->Read(KEY_SYMBOL, &strVal))
720 continue;
721
722 // Related to Bug2778: config file only remembered an internal name,
723 // so this symbol may not contain the correct TranslatableString.
724 // See calls to IsPluginRegistered which can correct that.
725 plug.SetSymbol(strVal);
726
727 // Get the version and bypass group if not found
728 if (!pRegistry->Read(KEY_VERSION, &strVal))
729 {
730 continue;
731 }
732 plug.SetVersion(strVal);
733
734 // Get the vendor and bypass group if not found
735 if (!pRegistry->Read(KEY_VENDOR, &strVal))
736 {
737 continue;
738 }
739 plug.SetVendor( strVal );
740
741#if 0
742 // This was done before version 2.2.2, but the value was not really used
743 // But absence of a value will cause early versions to skip the group
744 // Therefore we still write a blank to keep pluginregistry.cfg
745 // backwards-compatible
746
747 // Get the description and bypass group if not found
748 if (!pRegistry->Read(KEY_DESCRIPTION, &strVal))
749 {
750 continue;
751 }
752#endif
753
754 // Is it enabled...default to no if not found
755 pRegistry->Read(KEY_ENABLED, &boolVal, false);
756 plug.SetEnabled(boolVal);
757
758 // Is it valid...default to no if not found
759 pRegistry->Read(KEY_VALID, &boolVal, false);
760 plug.SetValid(boolVal);
761
762 switch (type)
763 {
764 case PluginTypeModule:
765 {
766 // Nothing to do here yet
767 }
768 break;
769
770 case PluginTypeEffect:
771 {
772 // Get the effect type and bypass group if not found
773 if (!pRegistry->Read(KEY_EFFECTTYPE, &strVal))
774 continue;
775
776 if (strVal == KEY_EFFECTTYPE_NONE)
778 else if (strVal == KEY_EFFECTTYPE_ANALYZE)
780 else if (strVal == KEY_EFFECTTYPE_GENERATE)
782 else if (strVal == KEY_EFFECTTYPE_PROCESS)
784 else if (strVal == KEY_EFFECTTYPE_TOOL)
786 else if (strVal == KEY_EFFECTTYPE_HIDDEN)
788 else
789 continue;
790
791 // Get the effect family and bypass group if not found
792 if (!pRegistry->Read(KEY_EFFECTFAMILY, &strVal))
793 {
794 continue;
795 }
796 plug.SetEffectFamily(strVal);
797
798 // Is it a default (above the line) effect and bypass group if not found
799 if (!pRegistry->Read(KEY_EFFECTDEFAULT, &boolVal))
800 {
801 continue;
802 }
803 plug.SetEffectDefault(boolVal);
804
805 // Is it an interactive effect and bypass group if not found
806 if (!pRegistry->Read(KEY_EFFECTINTERACTIVE, &boolVal))
807 {
808 continue;
809 }
810 plug.SetEffectInteractive(boolVal);
811
812 // Is it a realtime capable effect and bypass group if not found
813 if (!pRegistry->Read(KEY_EFFECTREALTIME, &strVal))
814 {
815 continue;
816 }
817 plug.DeserializeRealtimeSupport(strVal);
818
819 // Does the effect support automation...bypass group if not found
820 if (!pRegistry->Read(KEY_EFFECTAUTOMATABLE, &boolVal))
821 {
822 continue;
823 }
824 plug.SetEffectAutomatable(boolVal);
825 }
826 break;
827
829 {
830 // Get the importer identifier and bypass group if not found
831 if (!pRegistry->Read(KEY_IMPORTERIDENT, &strVal))
832 {
833 continue;
834 }
835 plug.SetImporterIdentifier(strVal);
836
837 // Get the importer extensions and bypass group if not found
838 if (!pRegistry->Read(KEY_IMPORTEREXTENSIONS, &strVal))
839 {
840 continue;
841 }
842 FileExtensions extensions;
843 wxStringTokenizer tkr(strVal, wxT(":"));
844 while (tkr.HasMoreTokens())
845 {
846 extensions.push_back(tkr.GetNextToken());
847 }
848 plug.SetImporterExtensions(extensions);
849 }
850 break;
851
852 case PluginTypeStub:
853 {
854 // Nothing additional for stubs
855 }
856 break;
857
858 // Not used by 2.1.1 or greater and should be removed after a few releases past 2.1.0.
859 case PluginTypeNone:
860 {
861 // Used for stub groups
862 }
863 break;
864
865 default:
866 {
867 continue;
868 }
869 }
870
871 // Everything checked out...accept the plugin
872 mRegisteredPlugins[groupName] = std::move(plug);
873 }
874
875 return;
876}
877
879{
880 // Create/Open the registry
881 auto pRegistry = sFactory(FileNames::PluginRegistry());
882 auto &registry = *pRegistry;
883
884 // Clear pluginregistry.cfg (not audacity.cfg)
885 registry.DeleteAll();
886
887 // Save the individual groups
888 SaveGroup(&registry, PluginTypeEffect);
889 SaveGroup(&registry, PluginTypeExporter);
891 SaveGroup(&registry, PluginTypeImporter);
892 SaveGroup(&registry, PluginTypeStub);
893
894 // Not used by 2.1.1 or greater, but must save to allow users to switch between 2.1.0
895 // and 2.1.1+. This should be removed after a few releases past 2.1.0.
896 //SaveGroup(&registry, PluginTypeNone);
897
898 // And now the providers
899 SaveGroup(&registry, PluginTypeModule);
900
901 // Write the version string
902 registry.Write(REGVERKEY, REGVERCUR);
903
904 // Just to be safe
905 registry.Flush();
906
908}
909
911{
912 return mRegver;
913}
914
916{
917 wxString group = GetPluginTypeString(type);
918 for (auto &pair : mRegisteredPlugins) {
919 auto & plug = pair.second;
920
921 if (plug.GetPluginType() != type)
922 {
923 continue;
924 }
925
926 pRegistry->SetPath(REGROOT + group + wxCONFIG_PATH_SEPARATOR + ConvertID(plug.GetID()));
927
928 pRegistry->Write(KEY_PATH, plug.GetPath());
929
930 // See comments with the corresponding load-time call to SetSymbol().
931 pRegistry->Write(KEY_SYMBOL, plug.GetSymbol().Internal());
932
933 // PRL: Writing KEY_NAME which is no longer read, but older Audacity
934 // versions expect to find it.
935 pRegistry->Write(KEY_NAME, plug.GetSymbol().Msgid().MSGID());
936
937 pRegistry->Write(KEY_VERSION, plug.GetUntranslatedVersion());
938 pRegistry->Write(KEY_VENDOR, plug.GetVendor());
939 // Write a blank -- see comments in LoadGroup:
940 pRegistry->Write(KEY_DESCRIPTION, wxString{});
941 pRegistry->Write(KEY_PROVIDERID, plug.GetProviderID());
942 pRegistry->Write(KEY_ENABLED, plug.IsEnabled());
943 pRegistry->Write(KEY_VALID, plug.IsValid());
944
945 switch (type)
946 {
947 case PluginTypeModule:
948 break;
949
950 case PluginTypeEffect:
951 {
952 EffectType etype = plug.GetEffectType();
953 wxString stype;
954 if (etype == EffectTypeNone)
955 stype = KEY_EFFECTTYPE_NONE;
956 else if (etype == EffectTypeAnalyze)
958 else if (etype == EffectTypeGenerate)
960 else if (etype == EffectTypeProcess)
962 else if (etype == EffectTypeTool)
963 stype = KEY_EFFECTTYPE_TOOL;
964 else if (etype == EffectTypeHidden)
965 stype = KEY_EFFECTTYPE_HIDDEN;
966
967 pRegistry->Write(KEY_EFFECTTYPE, stype);
968 pRegistry->Write(KEY_EFFECTFAMILY, plug.GetEffectFamily());
969 pRegistry->Write(KEY_EFFECTDEFAULT, plug.IsEffectDefault());
970 pRegistry->Write(KEY_EFFECTINTERACTIVE, plug.IsEffectInteractive());
971 pRegistry->Write(KEY_EFFECTREALTIME, plug.SerializeRealtimeSupport());
972 pRegistry->Write(KEY_EFFECTAUTOMATABLE, plug.IsEffectAutomatable());
973 }
974 break;
975
977 {
978 pRegistry->Write(KEY_IMPORTERIDENT, plug.GetImporterIdentifier());
979 const auto & extensions = plug.GetImporterExtensions();
980 wxString strExt;
981 for (size_t i = 0, cnt = extensions.size(); i < cnt; i++)
982 {
983 strExt += extensions[i] + wxT(":");
984 }
985 strExt.RemoveLast(1);
986 pRegistry->Write(KEY_IMPORTEREXTENSIONS, strExt);
987 }
988 break;
989
990 default:
991 break;
992 }
993 }
994
995 return;
996}
997
998// Here solely for the purpose of Nyquist Workbench until
999// a better solution is devised.
1001 std::unique_ptr<EffectDefinitionInterface> effect, PluginType type)
1002{
1003 PluginDescriptor & plug =
1004 CreatePlugin(GetID(effect.get()), effect.get(), type);
1005
1006 plug.SetEffectType(effect->GetType());
1007 plug.SetEffectFamily(effect->GetFamily().Internal());
1008 plug.SetEffectInteractive(effect->IsInteractive());
1009 plug.SetEffectDefault(effect->IsDefault());
1010 plug.SetRealtimeSupport(effect->RealtimeSupport());
1011 plug.SetEffectAutomatable(effect->SupportsAutomation());
1012
1013 plug.SetEffectLegacy(true);
1014 plug.SetEnabled(true);
1015 plug.SetValid(true);
1016
1017 mLoadedInterfaces[plug.GetID()] = std::move(effect);
1018
1019 return plug.GetID();
1020}
1021
1023{
1024 mRegisteredPlugins.erase(ID);
1025 mLoadedInterfaces.erase(ID);
1026}
1027
1029{
1030 return count_if(mRegisteredPlugins.begin(), mRegisteredPlugins.end(), [type](auto &pair){
1031 return pair.second.GetPluginType() == type; });
1032}
1033
1035{
1036 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1037 return nullptr;
1038 else
1039 return &iter->second;
1040}
1041
1043{
1044 const auto end = mPm.mRegisteredPlugins.end();
1045 if (incrementing && mIterator != end)
1046 ++mIterator;
1048 for (; mIterator != end; ++mIterator) {
1049 auto &plug = mIterator->second;
1050 if (!all && !(plug.IsValid() && plug.IsEnabled()))
1051 continue;
1052 auto plugType = plug.GetPluginType();
1053 if ((mPluginType == PluginTypeNone || (plugType & mPluginType)) &&
1054 (mEffectType == EffectTypeNone || plug.GetEffectType() == mEffectType)) {
1055 if (!all && (plugType & PluginTypeEffect)) {
1056 // This preference may be written by EffectsPrefs
1057 auto setting = mPm.GetPluginEnabledSetting( plug );
1058 if (!(setting.empty() || gPrefs->Read( setting, true )))
1059 continue;
1060 }
1061 // Pause iteration at this match
1062 break;
1063 }
1064 }
1065}
1066
1068: mPm{ manager }
1069, mIterator{ manager.mRegisteredPlugins.begin() }
1070{
1071}
1072
1074: mPm{ manager }
1075, mIterator{ manager.mRegisteredPlugins.begin() }
1076, mPluginType{ type }
1077{
1078 Advance(false);
1079}
1080
1082: mPm{ manager }
1083, mIterator{ manager.mRegisteredPlugins.begin() }
1084, mEffectType{ type }
1085{
1086 Advance(false);
1087}
1088
1090{
1091 Advance(true);
1092 return *this;
1093}
1094
1096{
1097 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1098 return false;
1099 else
1100 return iter->second.IsEnabled();
1101}
1102
1103void PluginManager::EnablePlugin(const PluginID & ID, bool enable)
1104{
1105 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1106 return;
1107 else
1108 iter->second.SetEnabled(enable);
1109}
1110
1112{
1113 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end()) {
1114 static ComponentInterfaceSymbol empty;
1115 return empty;
1116 }
1117 else
1118 return iter->second.GetSymbol();
1119}
1120
1122{
1123 if(auto it = mLoadedInterfaces.find(ID); it != mLoadedInterfaces.end())
1124 return it->second.get();
1125
1126 if(auto it = mRegisteredPlugins.find(ID); it != mRegisteredPlugins.end())
1127 {
1128 auto& desc = it->second;
1129 if(desc.GetPluginType() == PluginTypeModule)
1130 //it's very likely that this code path is not used
1131 return ModuleManager::Get().CreateProviderInstance(desc.GetID(), desc.GetPath());
1132
1133 if(auto provider = ModuleManager::Get().CreateProviderInstance(desc.GetProviderID(), wxEmptyString))
1134 {
1135 auto pluginInterface = provider->LoadPlugin(desc.GetPath());
1136 auto result = pluginInterface.get();
1137 mLoadedInterfaces[desc.GetID()] = std::move(pluginInterface);
1138 return result;
1139 }
1140 }
1141 return nullptr;
1142}
1143
1144std::vector<std::pair<wxString, wxString>> PluginManager::CheckPluginUpdates()
1145{
1147 wxArrayString pathIndex;
1148 for (auto &pair : mRegisteredPlugins) {
1149 auto &plug = pair.second;
1150
1151 // Bypass 2.1.0 placeholders...remove this after a few releases past 2.1.0
1152 if (plug.GetPluginType() != PluginTypeNone)
1153 pathIndex.push_back(plug.GetPath().BeforeFirst(wxT(';')));
1154 }
1155
1156 // Scan for NEW ones.
1157 //
1158 // Because we use the plugins "path" as returned by the providers, we can actually
1159 // have multiple providers report the same path since, at this point, they only
1160 // know that the path might possibly be one supported by the provider.
1161 //
1162 // When the user enables the plugin, each provider that reported it will be asked
1163 // to register the plugin.
1164
1165 std::vector<std::pair<wxString, wxString>> newPaths;
1166 for (auto &pair : mRegisteredPlugins) {
1167 auto &plug = pair.second;
1168 const PluginID & plugID = plug.GetID();
1169 const wxString & plugPath = plug.GetPath();
1170 PluginType plugType = plug.GetPluginType();
1171
1172 // Bypass 2.1.0 placeholders...remove this after a few releases past 2.1.0
1173 if (plugType == PluginTypeNone)
1174 continue;
1175
1176 if ( plugType == PluginTypeModule )
1177 {
1178 if (!mm.IsProviderValid(plugID, plugPath))
1179 {
1180 plug.SetEnabled(false);
1181 plug.SetValid(false);
1182 }
1183 else
1184 {
1185 if (auto provider = mm.CreateProviderInstance( plugID, plugPath ))
1186 {
1187 const auto paths = provider->FindModulePaths(*this);
1188 for (size_t i = 0, cnt = paths.size(); i < cnt; i++)
1189 {
1190 wxString path = paths[i].BeforeFirst(wxT(';'));
1191 if(!make_iterator_range(pathIndex).contains(path))
1192 newPaths.push_back(std::make_pair(plugID, path));
1193 }
1194 }
1195 }
1196 }
1197 else if (plugType != PluginTypeStub)
1198 {
1199 plug.SetValid(mm.IsPluginValid(plug.GetProviderID(), plugPath, false));
1200 if (!plug.IsValid())
1201 plug.SetEnabled(false);
1202 }
1203 }
1204
1205 return newPaths;
1206}
1207
1209{
1210 return ModuleManager::GetID(provider);
1211}
1212
1214{
1215 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1217 wxEmptyString,
1218 command->GetVendor().Internal(),
1219 command->GetSymbol().Internal(),
1220 command->GetPath());
1221}
1222
1224{
1225 return wxString::Format(wxT("%s_%s_%s_%s_%s"),
1227 effect->GetFamily().Internal(),
1228 effect->GetVendor().Internal(),
1229 effect->GetSymbol().Internal(),
1230 effect->GetPath());
1231}
1232
1234{
1235 return wxJoin(wxArrayStringEx{
1237 effect->GetFamily().Internal(),
1238 effect->GetVendor().Internal(),
1239 effect->GetSymbol().Internal(),
1240 effect->GetPath()
1241 }, '_');
1242}
1243
1245{
1246 auto strings = wxSplit(ID, '_');
1247 if (strings.size() == 5)
1248 return strings[3];
1249 return {};
1250}
1251
1252// This string persists in configuration files
1253// So config compatibility will break if it is changed across Audacity versions
1255{
1256 wxString str;
1257
1258 switch (type)
1259 {
1260 default:
1261 case PluginTypeNone:
1262 str = wxT("Placeholder");
1263 break;
1264 case PluginTypeStub:
1265 str = wxT("Stub");
1266 break;
1267 case PluginTypeEffect:
1268 str = wxT("Effect");
1269 break;
1271 str = wxT("Generic");
1272 break;
1273 case PluginTypeExporter:
1274 str = wxT("Exporter");
1275 break;
1276 case PluginTypeImporter:
1277 str = wxT("Importer");
1278 break;
1279 case PluginTypeModule:
1281 break;
1282 }
1283
1284 return str;
1285}
1286
1289 PluginType type)
1290{
1291 // This will either create a NEW entry or replace an existing entry
1293
1294 plug.SetPluginType(type);
1295
1296 plug.SetID(id);
1297 plug.SetPath(ident->GetPath());
1298 plug.SetSymbol(ident->GetSymbol());
1299 plug.SetVendor(ident->GetVendor().Internal());
1300 plug.SetVersion(ident->GetVersion());
1301
1302 return plug;
1303}
1304
1306{
1307 if (!mSettings)
1308 {
1310
1311 // Check for a settings version that we can understand
1312 if (mSettings->HasEntry(SETVERKEY))
1313 {
1314 wxString setver = mSettings->Read(SETVERKEY, SETVERKEY);
1315 if (setver < SETVERCUR )
1316 {
1317 // This is where we'd put in conversion code when the
1318 // settings version changes.
1319 //
1320 // Should also check for a settings file that is newer than
1321 // what we can understand.
1322 }
1323 }
1324 else
1325 {
1326 // Make sure is has a version string
1327 mSettings->Write(SETVERKEY, SETVERCUR);
1328 mSettings->Flush();
1329 }
1330 }
1331
1332 return mSettings.get();
1333}
1334
1336{
1337 auto settings = GetSettings();
1338
1339 bool res = settings->HasGroup(group);
1340 if (res)
1341 {
1342 // The group exists, but empty groups aren't considered valid
1343 wxString oldPath = settings->GetPath();
1344 settings->SetPath(group);
1345 res = settings->GetNumberOfEntries() || settings->GetNumberOfGroups();
1346 settings->SetPath(oldPath);
1347 }
1348
1349 return res;
1350}
1351
1353{
1354 if (group.empty() || !HasGroup(group))
1355 {
1356 return false;
1357 }
1358
1359 wxString path = GetSettings()->GetPath();
1360 GetSettings()->SetPath(group);
1361
1362 wxString name;
1363 long index = 0;
1364 if (GetSettings()->GetFirstGroup(name, index))
1365 {
1366 do
1367 {
1368 subgroups.push_back(name);
1369 } while (GetSettings()->GetNextGroup(name, index));
1370 }
1371
1372 GetSettings()->SetPath(path);
1373
1374 return true;
1375}
1376
1378{
1379 return GetSettings()->Exists(key);
1380}
1381
1384{
1385 if (key.empty())
1386 return false;
1387 const auto visitor = [&](const auto var){
1388 const auto pVar = &var.get();
1389 // precondition is that defval wraps same type as var
1390 using Type = typename decltype(var)::type;
1391 const auto pDefval =
1392 std::get_if<std::reference_wrapper<const Type>>(&defval);
1393 if constexpr( std::is_same_v<Type, float> ) {
1394 double temp;
1395 if( GetSettings()->Read(key, &temp, *pDefval) ) {
1396 *pVar = static_cast<float>(temp);
1397 return true;
1398 }
1399 return false;
1400 }
1401 else
1402 return GetSettings()->Read(key, pVar, *pDefval);
1403 };
1404 return Visit(visitor, var);
1405}
1406
1408 const RegistryPath & key, ConfigConstReference value)
1409{
1410 if (key.empty())
1411 return false;
1412 const auto visitor = [&](const auto value){
1413 return GetSettings()->Write(key, value.get()) && GetSettings()->Flush();
1414 };
1415 return Visit(visitor, value);
1416}
1417
1418/* Return value is a key for lookup in a config file */
1420 ConfigurationType type, const PluginID & ID)
1421{
1422 bool shared = (type == ConfigurationType::Shared);
1423
1424 // All the strings reported by PluginDescriptor and used in this function
1425 // persist in the plugin settings configuration file, so they should not
1426 // be changed across Audacity versions, or else compatibility of the
1427 // configuration files will break.
1428
1429 if (auto iter = mRegisteredPlugins.find(ID); iter == mRegisteredPlugins.end())
1430 return {};
1431 else {
1432 const PluginDescriptor & plug = iter->second;
1433
1434 wxString id = GetPluginTypeString(plug.GetPluginType()) +
1435 wxT("_") +
1436 plug.GetEffectFamily() + // is empty for non-Effects
1437 wxT("_") +
1438 plug.GetVendor() +
1439 wxT("_") +
1440 (shared ? wxString{} : plug.GetSymbol().Internal());
1441
1442 return SETROOT +
1443 ConvertID(id) +
1444 wxCONFIG_PATH_SEPARATOR +
1445 (shared ? wxT("shared") : wxT("private")) +
1446 wxCONFIG_PATH_SEPARATOR;
1447 }
1448}
1449
1450/* Return value is a key for lookup in a config file */
1452 const PluginID & ID, const RegistryPath & group)
1453{
1454 auto path = SettingsPath(type, ID);
1455
1456 wxFileName ff(group);
1457 if (!ff.GetName().empty())
1458 {
1459 path += ff.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
1460 }
1461
1462 return path;
1463}
1464
1465/* Return value is a key for lookup in a config file */
1467 const RegistryPath & group, const RegistryPath & key)
1468{
1469 auto path = Group(type, ID, group);
1470 if (path.empty())
1471 {
1472 return path;
1473 }
1474
1475 return path + key;
1476}
1477
1478// Sanitize the ID...not the best solution, but will suffice until this
1479// is converted to XML. We use base64 encoding to preserve case.
1481{
1482 if (ID.StartsWith(wxT("base64:")))
1483 {
1484 wxString id = ID.Mid(7);
1485 ArrayOf<char> buf{ id.length() / 4 * 3 };
1486 id = wxString::FromUTF8(buf.get(), Base64::Decode(id, buf.get()));
1487 return id;
1488 }
1489
1490 const wxCharBuffer & buf = ID.ToUTF8();
1491 return wxT("base64:") + Base64::Encode(buf, strlen(buf));
1492}
1493
1494// This is defined out-of-line here, to keep ComponentInterface free of other
1495// #include directives.
1497{
1498 return GetSymbol().Msgid();
1499}
@ Internal
Indicates internal failure from Audacity.
static RegisteredToolbarFactory factory
Toolkit-neutral facade for basic user interface services.
static const AudacityProject::AttachedObjects::RegisteredFactory key
#define str(a)
const TranslatableString name
Definition: Distortion.cpp:82
EffectType
@ EffectTypeHidden
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeNone
@ EffectTypeTool
@ EffectTypeProcess
wxString PluginID
Definition: EffectManager.h:30
const TranslatableString desc
Definition: ExportPCM.cpp:58
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define XPC(sing, plur, n, c)
Definition: Internat.h:100
#define XO(s)
Definition: Internat.h:31
auto Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
Definition: MemoryX.h:603
#define safenew
Definition: MemoryX.h:10
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:423
static CommandHandlerObject & ident(AudacityProject &project)
PluginType
@ PluginTypeStub
@ PluginTypeModule
@ PluginTypeAudacityCommand
@ PluginTypeExporter
@ PluginTypeNone
@ PluginTypeEffect
@ PluginTypeImporter
bool Regver_lt(const PluginRegistryVersion &regver1, const PluginRegistryVersion &regver2)
bool Regver_le(const PluginRegistryVersion &regver1, const PluginRegistryVersion &regver2)
wxString PluginRegistryVersion
Type of plugin registry version information.
#define KEY_EFFECTAUTOMATABLE
#define REGVERKEY
#define KEY_PROVIDERID
#define KEY_SYMBOL
#define KEY_IMPORTEREXTENSIONS
#define KEY_EFFECTTYPE_TOOL
#define KEY_VENDOR
#define KEY_PATH
#define KEY_IMPORTERIDENT
#define KEY_EFFECTTYPE_GENERATE
#define SETROOT
#define KEY_EFFECTTYPE_PROCESS
#define KEY_EFFECTINTERACTIVE
#define KEY_EFFECTTYPE_HIDDEN
#define KEY_ENABLED
#define SETVERKEY
#define SETVERCUR
static PluginManager::FileConfigFactory sFactory
#define KEY_EFFECTREALTIME
#define REGROOT
#define KEY_VERSION
#define KEY_EFFECTTYPE_NONE
#define KEY_EFFECTTYPE
#define KEY_EFFECTFAMILY
#define KEY_NAME
#define KEY_VALID
#define KEY_EFFECTTYPE_ANALYZE
#define KEY_DESCRIPTION
#define KEY_EFFECTDEFAULT
constexpr auto REGVERCUR
#define NYQUIST_PROMPT_ID
Generalized interface for discovery of plug-ins for one protocol.
FileConfig * gPrefs
Definition: Prefs.cpp:71
static const AttachedProjectObjects::RegisteredFactory manager
static TranslatableStrings names
Definition: TagsEditor.cpp:151
static Settings & settings()
Definition: TrackInfo.cpp:87
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
int id
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.
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.
virtual bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty=true) wxOVERRIDE
Definition: FileConfig.cpp:209
virtual bool GetNextGroup(wxString &str, long &lIndex) const wxOVERRIDE
Definition: FileConfig.cpp:108
virtual bool DeleteGroup(const wxString &key) wxOVERRIDE
Definition: FileConfig.cpp:219
virtual bool GetFirstGroup(wxString &str, long &lIndex) const wxOVERRIDE
Definition: FileConfig.cpp:103
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
virtual const wxString & GetPath() const wxOVERRIDE
Definition: FileConfig.cpp:98
virtual void SetPath(const wxString &strPath) wxOVERRIDE
Definition: FileConfig.cpp:93
Abstract base class used in importing a file.
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
static ModuleManager & Get()
static PluginID GetID(PluginProvider *provider)
static wxString GetPluginTypeString()
PluginProvider * CreateProviderInstance(const PluginID &provider, const PluginPath &path)
bool IsProviderValid(const PluginID &provider, const PluginPath &path)
bool IsPluginValid(const PluginID &provider, const PluginPath &path, bool bFast)
static const FilePath & GetExecutablePath()
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)
void SetID(const PluginID &ID)
void SetEffectType(EffectType type)
void SetEffectFamily(const wxString &family)
void SetPluginType(PluginType type)
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,...
Definition: PluginManager.h:41
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::function< std::unique_ptr< FileConfig >(const FilePath &localFilename) > FileConfigFactory
Definition: PluginManager.h:91
PluginRegistryVersion mRegver
void SaveGroup(FileConfig *pRegistry, PluginType type)
void Initialize(FileConfigFactory factory)
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 LoadGroup(FileConfig *pRegistry, PluginType type)
RegistryPath Group(ConfigurationType type, const PluginID &ID, const RegistryPath &group)
bool HasConfigValue(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
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)
std::vector< std::pair< wxString, wxString > > CheckPluginUpdates()
Ensures that all currently registered plugins still exist and scans for new ones.
FileConfig * GetSettings()
static Identifier GetEffectNameFromID(const PluginID &ID)
static PluginID GetID(PluginProvider *provider)
bool HasGroup(const RegistryPath &group)
void Load()
Load from preferences.
Range PluginsOfType(int type)
PluginDescriptor & CreatePlugin(const PluginID &id, ComponentInterface *ident, PluginType type)
const PluginRegistryVersion & GetRegistryVersion() const override
RegistryPath Key(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key)
static std::unique_ptr< PluginManager > mInstance
RegistryPath GetPluginEnabledSetting(const PluginID &ID) const
bool DropFile(const wxString &fileName)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
void EnablePlugin(const PluginID &ID, bool enable)
void RegisterPlugin(PluginDescriptor &&desc)
bool RemoveConfig(ConfigurationType type, const PluginID &ID, const RegistryPath &group, const RegistryPath &key) override
std::unique_ptr< FileConfig > mSettings
PluginMap mRegisteredPlugins
void InitializePlugins()
wxString ConvertID(const PluginID &ID)
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)
bool RemoveConfigSubgroup(ConfigurationType type, const PluginID &ID, const RegistryPath &group) override
std::map< PluginID, std::unique_ptr< ComponentInterface > > mLoadedInterfaces
const ComponentInterfaceSymbol & GetSymbol(const PluginID &ID)
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.
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
STRINGS_API wxString Encode(const void *in, int len)
Definition: Base64.cpp:27
STRINGS_API int Decode(const wxString &in, void *out)
Definition: Base64.cpp:67
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:256
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()
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:98