mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 15:49:36 +02:00
2460 lines
63 KiB
C++
2460 lines
63 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
PluginManager.cpp
|
|
|
|
Leland Lucius
|
|
|
|
*******************************************************************//*!
|
|
|
|
\file PluginManager.cpp
|
|
\brief
|
|
|
|
*//*******************************************************************/
|
|
|
|
#include <algorithm>
|
|
|
|
#include "Audacity.h"
|
|
|
|
#include <wx/defs.h>
|
|
#include <wx/dialog.h>
|
|
#include <wx/dir.h>
|
|
#include <wx/dynarray.h>
|
|
#include <wx/dynlib.h>
|
|
#include <wx/hashmap.h>
|
|
#include <wx/filename.h>
|
|
#include <wx/icon.h>
|
|
#include <wx/imaglist.h>
|
|
#include <wx/list.h>
|
|
#include <wx/listctrl.h>
|
|
#include <wx/log.h>
|
|
#include <wx/string.h>
|
|
#include <wx/tokenzr.h>
|
|
#include <wx/wfstream.h>
|
|
|
|
#include "audacity/EffectInterface.h"
|
|
|
|
#include "AudacityApp.h"
|
|
#include "effects/EffectManager.h"
|
|
#include "FileNames.h"
|
|
#include "ModuleManager.h"
|
|
#include "PlatformCompatibility.h"
|
|
#include "Prefs.h"
|
|
#include "ShuttleGui.h"
|
|
#include "xml/XMLFileReader.h"
|
|
#include "xml/XMLWriter.h"
|
|
|
|
#include "PluginManager.h"
|
|
|
|
#include <wx/arrimpl.cpp>
|
|
|
|
WX_DECLARE_STRING_HASH_MAP(wxArrayString, ProviderMap);
|
|
|
|
// ============================================================================
|
|
//
|
|
//
|
|
//
|
|
// ============================================================================
|
|
#if wxUSE_ACCESSIBILITY
|
|
|
|
class CheckListAx: public wxWindowAccessible
|
|
{
|
|
public:
|
|
CheckListAx(wxListCtrl * window);
|
|
|
|
virtual ~ CheckListAx();
|
|
|
|
// Retrieves the address of an IDispatch interface for the specified child.
|
|
// All objects must support this property.
|
|
virtual wxAccStatus GetChild( int childId, wxAccessible **child );
|
|
|
|
// Gets the number of children.
|
|
virtual wxAccStatus GetChildCount( int *childCount );
|
|
|
|
// Gets the default action for this object (0) or > 0 (the action for a child).
|
|
// Return wxACC_OK even if there is no action. actionName is the action, or the empty
|
|
// string if there is no action.
|
|
// The retrieved string describes the action that is performed on an object,
|
|
// not what the object does as a result. For example, a toolbar button that prints
|
|
// a document has a default action of "Press" rather than "Prints the current document."
|
|
virtual wxAccStatus GetDefaultAction( int childId, wxString *actionName );
|
|
|
|
// Returns the description for this object or a child.
|
|
virtual wxAccStatus GetDescription( int childId, wxString *description );
|
|
|
|
// Gets the window with the keyboard focus.
|
|
// If childId is 0 and child is NULL, no object in
|
|
// this subhierarchy has the focus.
|
|
// If this object has the focus, child should be 'this'.
|
|
virtual wxAccStatus GetFocus( int *childId, wxAccessible **child );
|
|
|
|
// Returns help text for this object or a child, similar to tooltip text.
|
|
virtual wxAccStatus GetHelpText( int childId, wxString *helpText );
|
|
|
|
// Returns the keyboard shortcut for this object or child.
|
|
// Return e.g. ALT+K
|
|
virtual wxAccStatus GetKeyboardShortcut( int childId, wxString *shortcut );
|
|
|
|
// Returns the rectangle for this object (id = 0) or a child element (id > 0).
|
|
// rect is in screen coordinates.
|
|
virtual wxAccStatus GetLocation( wxRect& rect, int elementId );
|
|
|
|
// Gets the name of the specified object.
|
|
virtual wxAccStatus GetName( int childId, wxString *name );
|
|
|
|
// Returns a role constant.
|
|
virtual wxAccStatus GetRole( int childId, wxAccRole *role );
|
|
|
|
// Gets a variant representing the selected children
|
|
// of this object.
|
|
// Acceptable values:
|
|
// - a null variant (IsNull() returns TRUE)
|
|
// - a list variant (GetType() == wxT("list"))
|
|
// - an integer representing the selected child element,
|
|
// or 0 if this object is selected (GetType() == wxT("long"))
|
|
// - a "void*" pointer to a wxAccessible child object
|
|
virtual wxAccStatus GetSelections( wxVariant *selections );
|
|
|
|
// Returns a state constant.
|
|
virtual wxAccStatus GetState( int childId, long* state );
|
|
|
|
// Returns a localized string representing the value for the object
|
|
// or child.
|
|
virtual wxAccStatus GetValue( int childId, wxString *strValue );
|
|
|
|
void SetSelected( int item );
|
|
|
|
private:
|
|
wxListCtrl *mParent;
|
|
int mLastId;
|
|
};
|
|
|
|
CheckListAx::CheckListAx( wxListCtrl * window ):
|
|
wxWindowAccessible( window )
|
|
{
|
|
mParent = window;
|
|
mLastId = -1;
|
|
}
|
|
|
|
CheckListAx::~CheckListAx()
|
|
{
|
|
}
|
|
|
|
void CheckListAx::SetSelected( int item )
|
|
{
|
|
if (mLastId != -1)
|
|
{
|
|
NotifyEvent( wxACC_EVENT_OBJECT_SELECTIONREMOVE,
|
|
mParent,
|
|
wxOBJID_CLIENT,
|
|
mLastId );
|
|
mLastId = -1;
|
|
}
|
|
|
|
if (item != -1)
|
|
{
|
|
NotifyEvent( wxACC_EVENT_OBJECT_FOCUS,
|
|
mParent,
|
|
wxOBJID_CLIENT,
|
|
item + 1 );
|
|
|
|
NotifyEvent( wxACC_EVENT_OBJECT_SELECTION,
|
|
mParent,
|
|
wxOBJID_CLIENT,
|
|
item + 1 );
|
|
|
|
mLastId = item + 1;
|
|
}
|
|
}
|
|
|
|
// Retrieves the address of an IDispatch interface for the specified child.
|
|
// All objects must support this property.
|
|
wxAccStatus CheckListAx::GetChild( int childId, wxAccessible** child )
|
|
{
|
|
if( childId == wxACC_SELF )
|
|
{
|
|
*child = this;
|
|
}
|
|
else
|
|
{
|
|
*child = NULL;
|
|
}
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Gets the number of children.
|
|
wxAccStatus CheckListAx::GetChildCount( int *childCount )
|
|
{
|
|
*childCount = mParent->GetItemCount();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Gets the default action for this object (0) or > 0 (the action for a child).
|
|
// Return wxACC_OK even if there is no action. actionName is the action, or the empty
|
|
// string if there is no action.
|
|
// The retrieved string describes the action that is performed on an object,
|
|
// not what the object does as a result. For example, a toolbar button that prints
|
|
// a document has a default action of "Press" rather than "Prints the current document."
|
|
wxAccStatus CheckListAx::GetDefaultAction( int WXUNUSED(childId), wxString *actionName )
|
|
{
|
|
actionName->Clear();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns the description for this object or a child.
|
|
wxAccStatus CheckListAx::GetDescription( int WXUNUSED(childId), wxString *description )
|
|
{
|
|
description->Clear();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Gets the window with the keyboard focus.
|
|
// If childId is 0 and child is NULL, no object in
|
|
// this subhierarchy has the focus.
|
|
// If this object has the focus, child should be 'this'.
|
|
wxAccStatus CheckListAx::GetFocus( int *childId, wxAccessible **child )
|
|
{
|
|
*childId = 0;
|
|
*child = this;
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns help text for this object or a child, similar to tooltip text.
|
|
wxAccStatus CheckListAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
|
|
{
|
|
helpText->Clear();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns the keyboard shortcut for this object or child.
|
|
// Return e.g. ALT+K
|
|
wxAccStatus CheckListAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
|
|
{
|
|
shortcut->Clear();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns the rectangle for this object (id = 0) or a child element (id > 0).
|
|
// rect is in screen coordinates.
|
|
wxAccStatus CheckListAx::GetLocation( wxRect& rect, int elementId )
|
|
{
|
|
if( elementId == wxACC_SELF )
|
|
{
|
|
rect = mParent->GetRect();
|
|
rect.SetPosition( mParent->GetParent()->ClientToScreen( rect.GetPosition() ) );
|
|
}
|
|
else
|
|
{
|
|
if( elementId <= mParent->GetItemCount() )
|
|
{
|
|
mParent->GetItemRect( elementId - 1, rect, wxLIST_RECT_LABEL );
|
|
rect.SetPosition( mParent->ClientToScreen( rect.GetPosition() ) );
|
|
}
|
|
}
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Gets the name of the specified object.
|
|
wxAccStatus CheckListAx::GetName( int WXUNUSED(childId), wxString *name )
|
|
{
|
|
*name = mParent->GetName();
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns a role constant.
|
|
wxAccStatus CheckListAx::GetRole( int childId, wxAccRole *role )
|
|
{
|
|
if( childId == wxACC_SELF )
|
|
{
|
|
*role = wxROLE_SYSTEM_LIST;
|
|
}
|
|
else
|
|
{
|
|
*role = wxROLE_SYSTEM_LISTITEM;
|
|
}
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Gets a variant representing the selected children
|
|
// of this object.
|
|
// Acceptable values:
|
|
// - a null variant (IsNull() returns TRUE)
|
|
// - a list variant (GetType() == wxT("list"))
|
|
// - an integer representing the selected child element,
|
|
// or 0 if this object is selected (GetType() == wxT("long"))
|
|
// - a "void*" pointer to a wxAccessible child object
|
|
wxAccStatus CheckListAx::GetSelections( wxVariant * WXUNUSED(selections) )
|
|
{
|
|
return wxACC_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
// Returns a state constant.
|
|
wxAccStatus CheckListAx::GetState( int childId, long *state )
|
|
{
|
|
int flag = wxACC_STATE_SYSTEM_FOCUSABLE;
|
|
|
|
if( childId == wxACC_SELF )
|
|
{
|
|
flag |= wxACC_STATE_SYSTEM_FOCUSED;
|
|
}
|
|
else
|
|
{
|
|
wxListItem item;
|
|
|
|
item.SetId( childId - 1 );
|
|
item.SetState( wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED );
|
|
item.SetMask( wxLIST_MASK_IMAGE | wxLIST_MASK_STATE );
|
|
|
|
if( mParent->GetItem( item ) )
|
|
{
|
|
flag |= wxACC_STATE_SYSTEM_SELECTABLE;
|
|
|
|
long state = item.GetState();
|
|
|
|
if( state & wxLIST_STATE_FOCUSED )
|
|
{
|
|
flag |= wxACC_STATE_SYSTEM_FOCUSED;
|
|
}
|
|
|
|
if( state & wxLIST_STATE_SELECTED )
|
|
{
|
|
flag |= wxACC_STATE_SYSTEM_SELECTED;
|
|
}
|
|
|
|
if( item.GetImage() != 0 )
|
|
{
|
|
flag |= wxACC_STATE_SYSTEM_CHECKED;
|
|
}
|
|
}
|
|
}
|
|
|
|
*state = flag;
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
// Returns a localized string representing the value for the object
|
|
// or child.
|
|
wxAccStatus CheckListAx::GetValue( int childId, wxString *strValue )
|
|
{
|
|
if( childId == 0 )
|
|
{
|
|
return wxACC_OK;
|
|
}
|
|
else
|
|
{
|
|
*strValue = mParent->GetItemText( childId - 1 );
|
|
}
|
|
|
|
return wxACC_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
// ============================================================================
|
|
//
|
|
//
|
|
//
|
|
// ============================================================================
|
|
|
|
#include "../images/Unchecked.xpm"
|
|
#include "../images/Checked.xpm"
|
|
#include "../images/Arrow15x15.xpm"
|
|
|
|
#define EffectListID 7001
|
|
#define EffectClearAllID 7002
|
|
#define EffectSelectAllID 7003
|
|
|
|
int wxCALLBACK SortCompare(long item1, long item2, long WXUNUSED(sortData))
|
|
{
|
|
wxString *str1 = (wxString *) item1;
|
|
wxString *str2 = (wxString *) item2;
|
|
|
|
#if defined(__WXMAC__)
|
|
return str2->Cmp(*str1);
|
|
#else
|
|
return str1->Cmp(*str2);
|
|
#endif
|
|
}
|
|
|
|
class PluginRegistrationDialog : public wxDialog
|
|
{
|
|
public:
|
|
// constructors and destructors
|
|
PluginRegistrationDialog(ProviderMap & map);
|
|
virtual ~PluginRegistrationDialog();
|
|
|
|
private:
|
|
void Populate();
|
|
void PopulateOrExchange(ShuttleGui & S);
|
|
|
|
void OnOK(wxCommandEvent & evt);
|
|
void OnCancel(wxCommandEvent & evt);
|
|
void OnListChar(wxKeyEvent & evt);
|
|
void OnListMouseDown(wxMouseEvent & evt);
|
|
void OnSelectAll(wxCommandEvent & evt);
|
|
void OnClearAll(wxCommandEvent & evt);
|
|
|
|
void SetBoldOrRegular(int i);
|
|
void SetState(int i, int state);
|
|
void ToggleItem(int i);
|
|
|
|
private:
|
|
ModuleInterface *mMod;
|
|
|
|
#if wxUSE_ACCESSIBILITY
|
|
CheckListAx *mAx;
|
|
#endif
|
|
|
|
wxListCtrl *mEffects;
|
|
PluginIDList mProvs;
|
|
wxArrayString mPaths;
|
|
wxArrayInt miState;
|
|
|
|
bool mCancelClicked;
|
|
|
|
ProviderMap & mMap;
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
BEGIN_EVENT_TABLE(PluginRegistrationDialog, wxDialog)
|
|
EVT_BUTTON(wxID_OK, PluginRegistrationDialog::OnOK)
|
|
EVT_BUTTON(wxID_CANCEL, PluginRegistrationDialog::OnCancel)
|
|
EVT_BUTTON(EffectClearAllID, PluginRegistrationDialog::OnClearAll)
|
|
EVT_BUTTON(EffectSelectAllID, PluginRegistrationDialog::OnSelectAll)
|
|
END_EVENT_TABLE()
|
|
|
|
PluginRegistrationDialog::PluginRegistrationDialog(ProviderMap & map)
|
|
: wxDialog(wxGetApp().GetTopWindow(),
|
|
wxID_ANY,
|
|
_("Register Effects"),
|
|
wxDefaultPosition, wxDefaultSize,
|
|
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
|
|
mMap(map)
|
|
{
|
|
mEffects = NULL;
|
|
SetLabel(_("Register Effects")); // Provide visual label
|
|
SetName(_("Register Effects")); // Provide audible label
|
|
Populate();
|
|
SetReturnCode(wxID_OK);
|
|
}
|
|
|
|
PluginRegistrationDialog::~PluginRegistrationDialog()
|
|
{
|
|
mEffects->Disconnect(wxEVT_LEFT_DOWN,
|
|
wxMouseEventHandler(PluginRegistrationDialog::OnListMouseDown),
|
|
NULL,
|
|
this);
|
|
mEffects->Disconnect(wxEVT_KEY_DOWN,
|
|
wxKeyEventHandler(PluginRegistrationDialog::OnListChar),
|
|
NULL,
|
|
this);
|
|
|
|
for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++)
|
|
{
|
|
wxString *str = (wxString *) mEffects->GetItemData(i);
|
|
if (str)
|
|
{
|
|
delete str;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PluginRegistrationDialog::Populate()
|
|
{
|
|
//------------------------- Main section --------------------
|
|
ShuttleGui S(this, eIsCreating);
|
|
PopulateOrExchange(S);
|
|
// ----------------------- End of main section --------------
|
|
}
|
|
|
|
/// Defines the dialog and does data exchange with it.
|
|
void PluginRegistrationDialog::PopulateOrExchange(ShuttleGui &S)
|
|
{
|
|
wxImageList * pImageList = new wxImageList( 15, 15 );
|
|
|
|
#define SHOW_UNCHECKED (0)
|
|
#define SHOW_CHECKED (1)
|
|
#define SHOW_ARROW (2)
|
|
|
|
#define COL_NAME (0)
|
|
#define COL_PATH (1)
|
|
|
|
pImageList->Add(wxBitmap(unchecked_xpm));
|
|
pImageList->Add(wxBitmap(checked_xpm));
|
|
pImageList->Add(wxBitmap(arrow15x15_xpm));
|
|
|
|
S.StartVerticalLay(true);
|
|
{
|
|
/*i18n-hint: The dialog shows a list of plugins with check-boxes
|
|
beside each one.*/
|
|
S.StartStatic(_("&Select Plug-ins to Install or press ENTER to Install All"), true);
|
|
{
|
|
S.SetStyle(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_HRULES | wxLC_VRULES );
|
|
mEffects = S.Id(EffectListID).AddListControlReportMode();
|
|
mEffects->Connect(wxEVT_LEFT_DOWN,
|
|
wxMouseEventHandler(PluginRegistrationDialog::OnListMouseDown),
|
|
NULL,
|
|
this);
|
|
mEffects->Connect(wxEVT_KEY_DOWN,
|
|
wxKeyEventHandler(PluginRegistrationDialog::OnListChar),
|
|
NULL,
|
|
this);
|
|
#if wxUSE_ACCESSIBILITY
|
|
mAx = new CheckListAx(mEffects);
|
|
mEffects->SetAccessible(mAx);
|
|
#endif
|
|
mEffects->AssignImageList( pImageList, wxIMAGE_LIST_SMALL );
|
|
mEffects->InsertColumn(COL_NAME, _("Plug-in Name"));
|
|
mEffects->InsertColumn(COL_PATH, _("Path"));
|
|
}
|
|
S.EndStatic();
|
|
|
|
S.StartHorizontalLay(wxALIGN_LEFT | wxEXPAND, false);
|
|
{
|
|
S.SetBorder(10);
|
|
S.StartHorizontalLay(wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
|
{
|
|
S.AddSpace(12);
|
|
S.SetBorder(6);
|
|
S.Id(EffectSelectAllID).AddButton(_("Select &All"));
|
|
S.Id(EffectClearAllID).AddButton(_("Clea&r All"));
|
|
}
|
|
S.EndHorizontalLay();
|
|
|
|
S.StartHorizontalLay(wxALIGN_CENTER | wxEXPAND);
|
|
{
|
|
S.AddSpace(1);
|
|
}
|
|
S.EndHorizontalLay();
|
|
|
|
S.AddStandardButtons(eOkButton | eCancelButton);
|
|
}
|
|
S.EndHorizontalLay();
|
|
}
|
|
S.EndVerticalLay();
|
|
|
|
// The dc is used to compute the text width in pixels.
|
|
// FIXME: That works fine for PC, but apparently comes out too small for wxMAC.
|
|
// iLen is minimum width in pixels shown for the file names. 200 is reasonable.
|
|
int iNameLen = 0;
|
|
int iPathLen = 0;
|
|
int x, y;
|
|
wxRect iconrect;
|
|
|
|
int i = 0;
|
|
for (ProviderMap::iterator iter = mMap.begin(); iter != mMap.end(); iter++, i++)
|
|
{
|
|
miState.Add( SHOW_CHECKED );
|
|
|
|
wxFileName fname = iter->first;
|
|
wxString name = fname.GetName();
|
|
wxString path = iter->first;
|
|
|
|
mEffects->InsertItem(i, name, SHOW_CHECKED);
|
|
mEffects->SetItemPtrData(i, (wxUIntPtr) new wxString(name));
|
|
mEffects->SetItem(i, COL_PATH, path);
|
|
|
|
// Only need to get the icon width once
|
|
if (i == 0)
|
|
{
|
|
#if defined(__WXMAC__)
|
|
// wxMac doesn't return the ICON rectangle. It returns the
|
|
// rectangle for the first column and that even comes back
|
|
// with negative numbers sometimes.
|
|
//
|
|
// So, just guess.
|
|
wxIcon i1(unchecked_xpm);
|
|
wxIcon i2(checked_xpm);
|
|
wxIcon i3(arrow15x15_xpm);
|
|
iconrect.x = 4;
|
|
iconrect.width = wxMax(wxMax(i1.GetWidth(), i2.GetWidth()), i3.GetWidth());
|
|
#else
|
|
mEffects->GetItemRect( i, iconrect, wxLIST_RECT_ICON );
|
|
#endif
|
|
}
|
|
mEffects->GetTextExtent(name, &x, &y);
|
|
iNameLen = wxMax(iNameLen, x + iconrect.width + (iconrect.x * 2));
|
|
mEffects->GetTextExtent(path, &x, &y );
|
|
iPathLen = wxMax(iPathLen, x + iconrect.width + (iconrect.x * 2));
|
|
}
|
|
|
|
mEffects->SortItems(SortCompare, 0);
|
|
|
|
mEffects->SetColumnWidth(COL_NAME, iNameLen + /* fudge */ 5);
|
|
mEffects->SetColumnWidth(COL_PATH, iPathLen + /* fudge */ 5);
|
|
|
|
mEffects->SetSizeHints(iNameLen + iPathLen + /* fudge */ 15, 200);
|
|
if (mPaths.size() > 0)
|
|
{
|
|
// Make sure first item is selected/focused.
|
|
mEffects->SetFocus();
|
|
mEffects->SetItemState(0, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED);
|
|
#if wxUSE_ACCESSIBILITY
|
|
mAx->SetSelected(0);
|
|
#endif
|
|
}
|
|
Layout();
|
|
Fit();
|
|
SetSizeHints(GetSize());
|
|
// Parent window is usually not there yet, so centre on screen rather than on parent.
|
|
CenterOnScreen();
|
|
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnListMouseDown(wxMouseEvent & evt)
|
|
{
|
|
wxPoint p = evt.GetPosition();
|
|
int flags = wxLIST_HITTEST_ONITEM;
|
|
int item = mEffects->HitTest(p, flags);
|
|
|
|
if (item != wxNOT_FOUND)
|
|
{
|
|
ToggleItem(item);
|
|
}
|
|
|
|
evt.Skip();
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnListChar(wxKeyEvent & evt)
|
|
{
|
|
switch (evt.GetKeyCode())
|
|
{
|
|
case WXK_SPACE:
|
|
{
|
|
int iItem = mEffects->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
|
|
|
|
if (iItem != wxNOT_FOUND)
|
|
{
|
|
ToggleItem(iItem);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WXK_RETURN:
|
|
// Don't know why wxListCtrls prevent default dialog action,
|
|
// but they do, so handle it.
|
|
EmulateButtonClickIfPresent(GetAffirmativeId());
|
|
break;
|
|
|
|
default:
|
|
evt.Skip();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void PluginRegistrationDialog::SetBoldOrRegular(int i)
|
|
{
|
|
wxFont Font = mEffects->GetItemFont(i);
|
|
Font.SetWeight( (miState[i] == SHOW_CHECKED) ? wxFONTWEIGHT_BOLD : wxFONTWEIGHT_NORMAL);
|
|
mEffects->SetItemFont(i, Font);
|
|
}
|
|
|
|
// We can't capture mouse clicks, only selected and deselected.
|
|
// Clicking on a selected item does not generate any event.
|
|
// Therefore our workaround solution is to NEVER actually select.
|
|
// So whenever the code tries to , we cancel the selection.
|
|
// That way we continue to get events.
|
|
void PluginRegistrationDialog::SetState(int i, int state)
|
|
{
|
|
miState[i] = state;
|
|
mEffects->SetItemImage(i, miState[i]);
|
|
#if wxUSE_ACCESSIBILITY
|
|
mAx->SetSelected(i);
|
|
#endif
|
|
}
|
|
|
|
void PluginRegistrationDialog::ToggleItem(int i)
|
|
{
|
|
SetState(i, miState[i] == SHOW_CHECKED ? SHOW_UNCHECKED : SHOW_CHECKED);
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnSelectAll(wxCommandEvent & WXUNUSED(evt))
|
|
{
|
|
for (size_t i = 0, cnt = miState.size(); i < cnt; i++)
|
|
{
|
|
SetState(i, SHOW_CHECKED);
|
|
}
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnClearAll(wxCommandEvent & WXUNUSED(evt))
|
|
{
|
|
for (size_t i = 0, cnt = miState.size(); i < cnt; i++)
|
|
{
|
|
SetState(i, SHOW_UNCHECKED);
|
|
}
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnOK(wxCommandEvent & WXUNUSED(evt))
|
|
{
|
|
mCancelClicked = false;
|
|
FindWindowById(EffectListID)->Disable();
|
|
FindWindowById(wxID_OK)->Disable();
|
|
FindWindowById(EffectListID)->Disable();
|
|
FindWindowById(EffectClearAllID)->Disable();
|
|
FindWindowById(EffectSelectAllID)->Disable();
|
|
|
|
PluginManager & pm = PluginManager::Get();
|
|
ModuleManager & mm = ModuleManager::Get();
|
|
|
|
wxListItem li;
|
|
li.Clear();
|
|
for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt && !mCancelClicked; i++)
|
|
{
|
|
mEffects->EnsureVisible(i);
|
|
li.SetId(i);
|
|
li.SetColumn(COL_PATH);
|
|
li.SetMask(wxLIST_MASK_TEXT);
|
|
mEffects->GetItem(li);
|
|
wxString path = li.GetText();
|
|
|
|
// Create a placeholder descriptor to show we've seen this plugin before and not
|
|
// to show it as new the next time Audacity starts.
|
|
//
|
|
// Placeholder descriptors have a plugin type of PluginTypeNone and the ID is the
|
|
// path.
|
|
PluginDescriptor & plug = pm.mPlugins[path];
|
|
|
|
plug.SetID(path);
|
|
plug.SetPath(path);
|
|
plug.SetEnabled(false);
|
|
plug.SetValid(false);
|
|
|
|
if (miState[i] == SHOW_CHECKED)
|
|
{
|
|
mEffects->SetItemImage(i, SHOW_ARROW);
|
|
wxArrayString providers = mMap[path];
|
|
for (size_t j = 0, cnt = providers.GetCount(); j < cnt; j++)
|
|
{
|
|
if (mm.RegisterPlugin(providers[j], path))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
mEffects->SetItemImage(i, SHOW_CHECKED);
|
|
}
|
|
wxYield();
|
|
}
|
|
|
|
EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK);
|
|
}
|
|
|
|
void PluginRegistrationDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
|
|
{
|
|
mCancelClicked = true;
|
|
|
|
EndModal(mCancelClicked ? wxID_CANCEL : wxID_OK);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Plugindescriptor
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
PluginDescriptor::PluginDescriptor()
|
|
{
|
|
mPluginType = PluginTypeNone;
|
|
mEnabled = false;
|
|
mInstance = NULL;
|
|
|
|
mEffectType = EffectTypeNone;
|
|
mEffectInteractive = false;
|
|
mEffectDefault = false;
|
|
mEffectLegacy = false;
|
|
mEffectRealtime = false;
|
|
mEffectAutomatable = false;
|
|
}
|
|
|
|
PluginDescriptor::~PluginDescriptor()
|
|
{
|
|
if (mInstance)
|
|
{
|
|
ModuleManager::Get().DeleteInstance(GetProviderID(), mInstance);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool PluginDescriptor::IsInstantiated()
|
|
{
|
|
return mInstance != NULL;
|
|
}
|
|
|
|
IdentInterface *PluginDescriptor::GetInstance()
|
|
{
|
|
if (!mInstance)
|
|
{
|
|
if (GetPluginType() == PluginTypeModule)
|
|
{
|
|
mInstance = ModuleManager::Get().CreateProviderInstance(GetID(), GetPath());
|
|
}
|
|
else
|
|
{
|
|
mInstance = ModuleManager::Get().CreateInstance(GetProviderID(), GetID(), GetPath());
|
|
}
|
|
}
|
|
|
|
return mInstance;
|
|
}
|
|
|
|
void PluginDescriptor::SetInstance(IdentInterface *instance)
|
|
{
|
|
mInstance = instance;
|
|
|
|
return;
|
|
}
|
|
|
|
PluginType PluginDescriptor::GetPluginType() const
|
|
{
|
|
return mPluginType;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetPath() const
|
|
{
|
|
return mPath;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetName() const
|
|
{
|
|
return mName;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetVersion() const
|
|
{
|
|
return mVersion;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetVendor() const
|
|
{
|
|
return mVendor;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetDescription() const
|
|
{
|
|
return mDescription;
|
|
}
|
|
|
|
const PluginID & PluginDescriptor::GetID() const
|
|
{
|
|
return mID;
|
|
}
|
|
|
|
const PluginID & PluginDescriptor::GetProviderID() const
|
|
{
|
|
return mProviderID;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEnabled() const
|
|
{
|
|
return mEnabled;
|
|
}
|
|
|
|
bool PluginDescriptor::IsValid() const
|
|
{
|
|
return mValid;
|
|
}
|
|
|
|
wxString PluginDescriptor::GetMenuName() const
|
|
{
|
|
// This probably shouldn't be here...but it was easy
|
|
wxString name;
|
|
mName.EndsWith(wxT("..."), &name);
|
|
|
|
return (mVendor.IsEmpty() ? wxT("") : mVendor + wxT(": ")) +
|
|
(name.IsEmpty() ? mName : name) +
|
|
(mEffectInteractive ? wxT("...") : wxT(""));
|
|
}
|
|
|
|
void PluginDescriptor::SetPluginType(PluginType type)
|
|
{
|
|
mPluginType = type;
|
|
}
|
|
|
|
void PluginDescriptor::SetPath(const wxString & path)
|
|
{
|
|
mPath = path;
|
|
}
|
|
|
|
void PluginDescriptor::SetName(const wxString & name)
|
|
{
|
|
mName = name;
|
|
}
|
|
|
|
void PluginDescriptor::SetVersion(const wxString & version)
|
|
{
|
|
mVersion = version;
|
|
}
|
|
|
|
void PluginDescriptor::SetVendor(const wxString & vendor)
|
|
{
|
|
mVendor = vendor;
|
|
}
|
|
|
|
void PluginDescriptor::SetDescription(const wxString & description)
|
|
{
|
|
mDescription = description;
|
|
}
|
|
|
|
void PluginDescriptor::SetID(const PluginID & ID)
|
|
{
|
|
mID = ID;
|
|
}
|
|
|
|
void PluginDescriptor::SetProviderID(const PluginID & providerID)
|
|
{
|
|
mProviderID = providerID;
|
|
}
|
|
|
|
void PluginDescriptor::SetEnabled(bool enable)
|
|
{
|
|
mEnabled = enable;
|
|
}
|
|
|
|
void PluginDescriptor::SetValid(bool valid)
|
|
{
|
|
mValid = valid;
|
|
}
|
|
|
|
// Effects
|
|
|
|
const wxString & PluginDescriptor::GetEffectFamily() const
|
|
{
|
|
return mEffectFamily;
|
|
}
|
|
|
|
EffectType PluginDescriptor::GetEffectType() const
|
|
{
|
|
return mEffectType;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEffectInteractive() const
|
|
{
|
|
return mEffectInteractive;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEffectDefault() const
|
|
{
|
|
return mEffectDefault;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEffectLegacy() const
|
|
{
|
|
return mEffectLegacy;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEffectRealtime() const
|
|
{
|
|
return mEffectRealtime;
|
|
}
|
|
|
|
bool PluginDescriptor::IsEffectAutomatable() const
|
|
{
|
|
return mEffectAutomatable;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectFamily(const wxString & family)
|
|
{
|
|
mEffectFamily = family;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectType(EffectType type)
|
|
{
|
|
mEffectType = type;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectInteractive(bool interactive)
|
|
{
|
|
mEffectInteractive = interactive;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectDefault(bool dflt)
|
|
{
|
|
mEffectDefault = dflt;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectLegacy(bool legacy)
|
|
{
|
|
mEffectLegacy = legacy;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectRealtime(bool realtime)
|
|
{
|
|
mEffectRealtime = realtime;
|
|
}
|
|
|
|
void PluginDescriptor::SetEffectAutomatable(bool automatable)
|
|
{
|
|
mEffectAutomatable = automatable;
|
|
}
|
|
|
|
// Importer
|
|
|
|
const wxString & PluginDescriptor::GetImporterIdentifier() const
|
|
{
|
|
return mImporterIdentifier;
|
|
}
|
|
|
|
void PluginDescriptor::SetImporterIdentifier(const wxString & identifier)
|
|
{
|
|
mImporterIdentifier = identifier;
|
|
}
|
|
|
|
const wxString & PluginDescriptor::GetImporterFilterDescription() const
|
|
{
|
|
return mImporterFilterDesc;
|
|
}
|
|
|
|
void PluginDescriptor::SetImporterFilterDescription(const wxString & filterDesc)
|
|
{
|
|
mImporterFilterDesc = filterDesc;
|
|
}
|
|
|
|
const wxArrayString & PluginDescriptor::GetImporterExtensions() const
|
|
{
|
|
return mImporterExtensions;
|
|
}
|
|
|
|
void PluginDescriptor::SetImporterExtensions(const wxArrayString & extensions)
|
|
{
|
|
mImporterExtensions = extensions;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PluginManager
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define CACHEROOT wxString(wxT("/plugincache/"))
|
|
|
|
#define KEY_ID wxT("ID")
|
|
#define KEY_NAME wxT("Name")
|
|
#define KEY_PATH wxT("Path")
|
|
#define KEY_VENDOR wxT("Vendor")
|
|
#define KEY_VERSION wxT("Version")
|
|
#define KEY_DESCRIPTION wxT("Description")
|
|
#define KEY_LASTUPDATED wxT("LastUpdated")
|
|
#define KEY_ENABLED wxT("Enabled")
|
|
#define KEY_VALID wxT("Valid")
|
|
#define KEY_PROVIDERID wxT("ProviderID")
|
|
#define KEY_EFFECTTYPE wxT("EffectType")
|
|
#define KEY_EFFECTFAMILY wxT("EffectFamily")
|
|
#define KEY_EFFECTDEFAULT wxT("EffectDefault")
|
|
#define KEY_EFFECTINTERACTIVE wxT("EffectInteractive")
|
|
#define KEY_EFFECTREALTIME wxT("EffectRealtime")
|
|
#define KEY_EFFECTAUTOMATABLE wxT("EffectAutomatable")
|
|
#define KEY_EFFECTTYPE_NONE wxT("None")
|
|
#define KEY_EFFECTTYPE_ANALYZE wxT("Analyze")
|
|
#define KEY_EFFECTTYPE_GENERATE wxT("Generate")
|
|
#define KEY_EFFECTTYPE_PROCESS wxT("Process")
|
|
#define KEY_IMPORTERIDENT wxT("ImporterIdent")
|
|
#define KEY_IMPORTERFILTER wxT("ImporterFilter")
|
|
#define KEY_IMPORTEREXTENSIONS wxT("ImporterExtensions")
|
|
|
|
// ============================================================================
|
|
//
|
|
// PluginManagerInterface implementation
|
|
//
|
|
// ============================================================================
|
|
|
|
void PluginManager::RegisterModulePlugin(IdentInterface *module)
|
|
{
|
|
PluginDescriptor & plug = CreatePlugin(module, PluginTypeModule);
|
|
|
|
plug.SetEnabled(true);
|
|
plug.SetValid(true);
|
|
}
|
|
|
|
void PluginManager::RegisterEffectPlugin(IdentInterface *provider, EffectIdentInterface *effect)
|
|
{
|
|
PluginDescriptor & plug = CreatePlugin(effect, PluginTypeEffect);
|
|
|
|
plug.SetProviderID(provider->GetID());
|
|
|
|
plug.SetEffectType(effect->GetType());
|
|
plug.SetEffectFamily(effect->GetFamily());
|
|
plug.SetEffectInteractive(effect->IsInteractive());
|
|
plug.SetEffectDefault(effect->IsDefault());
|
|
plug.SetEffectRealtime(effect->SupportsRealtime());
|
|
plug.SetEffectAutomatable(effect->SupportsAutomation());
|
|
|
|
plug.SetEnabled(true);
|
|
plug.SetValid(true);
|
|
}
|
|
|
|
void PluginManager::RegisterImporterPlugin(IdentInterface *provider, ImporterInterface *importer)
|
|
{
|
|
PluginDescriptor & plug = CreatePlugin(importer, PluginTypeImporter);
|
|
|
|
plug.SetProviderID(provider->GetID());
|
|
|
|
plug.SetImporterIdentifier(importer->GetPluginStringID());
|
|
plug.SetImporterFilterDescription(importer->GetPluginFormatDescription());
|
|
plug.SetImporterExtensions(importer->GetSupportedExtensions());
|
|
}
|
|
|
|
void PluginManager::FindFilesInPathList(const wxString & pattern,
|
|
const wxArrayString & pathList,
|
|
wxArrayString & files,
|
|
bool directories)
|
|
{
|
|
|
|
wxLogNull nolog;
|
|
|
|
// Why bother...
|
|
if (pattern.IsEmpty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: We REALLY need to figure out the "Audacity" plug-in path(s)
|
|
|
|
wxFileName f;
|
|
wxArrayString paths;
|
|
|
|
// Add the "per-user" plug-ins directory
|
|
f = FileNames::PlugInDir();
|
|
paths.Add(f.GetFullPath());
|
|
|
|
// Add the "Audacity" plug-ins directory
|
|
f = PlatformCompatibility::GetExecutablePath();
|
|
#if defined(__WXMAC__)
|
|
f.RemoveLastDir();
|
|
f.RemoveLastDir();
|
|
f.RemoveLastDir();
|
|
#endif
|
|
f.AppendDir(wxT("plug-ins"));
|
|
paths.Add(f.GetPath());
|
|
|
|
// Weed out duplicates
|
|
for (size_t i = 0, cnt = pathList.size(); i < cnt; i++)
|
|
{
|
|
f = pathList[i];
|
|
wxString path = f.GetFullPath();
|
|
if (paths.Index(path, wxFileName::IsCaseSensitive()) == wxNOT_FOUND)
|
|
{
|
|
paths.Add(path);
|
|
}
|
|
}
|
|
|
|
// Find all matching files in each path
|
|
for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++)
|
|
{
|
|
f = paths[i] + wxFILE_SEP_PATH + pattern;
|
|
wxDir::GetAllFiles(f.GetPath(), &files, f.GetFullName(), directories ? wxDIR_DEFAULT : wxDIR_FILES);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups)
|
|
{
|
|
return GetSubgroups(SharedGroup(ID, group), subgroups);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, float & value, float defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, double & value, double defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, sampleCount & value, sampleCount defval)
|
|
{
|
|
return GetConfig(SharedKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const wxString & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const int & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const bool & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const float & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetSharedConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value)
|
|
{
|
|
return SetConfig(SharedKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::RemoveSharedConfigSubgroup(const PluginID & ID, const wxString & group)
|
|
{
|
|
return mConfig->DeleteGroup(SharedGroup(ID, group));
|
|
}
|
|
|
|
bool PluginManager::RemoveSharedConfig(const PluginID & ID, const wxString & group, const wxString & key)
|
|
{
|
|
return mConfig->DeleteEntry(SharedKey(ID, group, key));
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfigSubgroups(const PluginID & ID, const wxString & group, wxArrayString & subgroups)
|
|
{
|
|
return GetSubgroups(PrivateGroup(ID, group), subgroups);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, wxString & value, const wxString & defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, int & value, int defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, bool & value, bool defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, float & value, float defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, double & value, double defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::GetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, sampleCount & value, sampleCount defval)
|
|
{
|
|
return GetConfig(PrivateKey(ID, group, key), value, defval);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const wxString & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const int & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const bool & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const float & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const double & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::SetPrivateConfig(const PluginID & ID, const wxString & group, const wxString & key, const sampleCount & value)
|
|
{
|
|
return SetConfig(PrivateKey(ID, group, key), value);
|
|
}
|
|
|
|
bool PluginManager::RemovePrivateConfigSubgroup(const PluginID & ID, const wxString & group)
|
|
{
|
|
return mConfig->DeleteGroup(PrivateGroup(ID, group));
|
|
}
|
|
|
|
bool PluginManager::RemovePrivateConfig(const PluginID & ID, const wxString & group, const wxString & key)
|
|
{
|
|
return mConfig->DeleteEntry(PrivateKey(ID, group, key));
|
|
}
|
|
|
|
// ============================================================================
|
|
//
|
|
// PluginManager
|
|
//
|
|
// ============================================================================
|
|
|
|
// The one and only PluginManager
|
|
PluginManager PluginManager::mInstance;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Creation/Destruction
|
|
// ----------------------------------------------------------------------------
|
|
|
|
PluginManager::PluginManager()
|
|
{
|
|
mConfig = NULL;
|
|
}
|
|
|
|
PluginManager::~PluginManager()
|
|
{
|
|
if (mConfig)
|
|
{
|
|
delete mConfig;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// PluginManager implementation
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ============================================================================
|
|
//
|
|
// Return reference to singleton
|
|
//
|
|
// (Thread-safe...no active threading during construction or after destruction)
|
|
// ============================================================================
|
|
|
|
PluginManager & PluginManager::Get()
|
|
{
|
|
return mInstance;
|
|
}
|
|
|
|
void PluginManager::Initialize()
|
|
{
|
|
// Always load the config first
|
|
bool loaded = Load();
|
|
|
|
// Then look for providers (they may autoregister plugins)
|
|
ModuleManager::Get().DiscoverProviders();
|
|
|
|
// And finally check for updates
|
|
CheckForUpdates(!loaded);
|
|
}
|
|
|
|
void PluginManager::Terminate()
|
|
{
|
|
if (mConfig)
|
|
{
|
|
Save();
|
|
delete mConfig;
|
|
mConfig = NULL;
|
|
}
|
|
|
|
// Get rid of all non-module plugins first
|
|
PluginMap::iterator iter = mPlugins.begin();
|
|
while (iter != mPlugins.end())
|
|
{
|
|
PluginDescriptor & plug = iter->second;
|
|
if (plug.GetPluginType() == PluginTypeEffect)
|
|
{
|
|
mPlugins.erase(iter++);
|
|
continue;
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
|
|
// Now get rid of the modules
|
|
iter = mPlugins.begin();
|
|
while (iter != mPlugins.end())
|
|
{
|
|
mPlugins.erase(iter++);
|
|
}
|
|
}
|
|
|
|
bool PluginManager::Load()
|
|
{
|
|
// IF already open THEN nothing to do.
|
|
if (mConfig != NULL)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Create the config
|
|
//
|
|
// TODO: I'd like to switch to XML using the TinyXML2 lib
|
|
mConfig = new wxFileConfig(wxEmptyString, wxEmptyString, FileNames::PluginsCache());
|
|
|
|
// If this group doesn't exist then we have the original format and we
|
|
// can't use it or even attempt a conversion, so just start with a fresh
|
|
// config.
|
|
if (!mConfig->HasGroup(CACHEROOT))
|
|
{
|
|
// Must start over
|
|
mConfig->DeleteAll();
|
|
return false;
|
|
}
|
|
|
|
// Load all provider plugins first
|
|
LoadGroup(wxT("modules"), PluginTypeModule);
|
|
|
|
// Now the rest
|
|
LoadGroup(wxT("effects"), PluginTypeEffect);
|
|
LoadGroup(wxT("exporters"), PluginTypeExporter);
|
|
LoadGroup(wxT("importers"), PluginTypeImporter);
|
|
|
|
LoadGroup(wxT("placeholders"), PluginTypeNone);
|
|
|
|
return true;
|
|
}
|
|
|
|
void PluginManager::LoadGroup(const wxChar * group, PluginType type)
|
|
{
|
|
wxString strVal;
|
|
bool boolVal;
|
|
wxString groupName;
|
|
long groupIndex;
|
|
wxString cfgPath = CACHEROOT + group + wxCONFIG_PATH_SEPARATOR;
|
|
|
|
mConfig->SetPath(cfgPath);
|
|
for (bool cont = mConfig->GetFirstGroup(groupName, groupIndex);
|
|
cont;
|
|
mConfig->SetPath(cfgPath),
|
|
cont = mConfig->GetNextGroup(groupName, groupIndex))
|
|
{
|
|
PluginDescriptor plug;
|
|
|
|
mConfig->SetPath(groupName);
|
|
|
|
groupName = ConvertID(groupName);
|
|
|
|
// Bypass group if the ID is already in use
|
|
if (mPlugins.find(groupName) != mPlugins.end())
|
|
{
|
|
mConfig->SetPath(wxT(".."));
|
|
|
|
continue;
|
|
}
|
|
|
|
// Set the ID and type
|
|
plug.SetID(groupName);
|
|
plug.SetPluginType(type);
|
|
|
|
// Get the provider ID and bypass group if not found
|
|
if (!mConfig->Read(KEY_PROVIDERID, &strVal, wxEmptyString))
|
|
{
|
|
// Bypass group if the provider isn't valid
|
|
if (!strVal.IsEmpty() && mPlugins.find(wxString(strVal)) == mPlugins.end())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
plug.SetProviderID(PluginID(strVal));
|
|
|
|
// Get the path (optional)
|
|
mConfig->Read(KEY_PATH, &strVal, wxEmptyString);
|
|
plug.SetPath(wxString(strVal));
|
|
|
|
// Get the name and bypass group if not found
|
|
if (!mConfig->Read(KEY_NAME, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetName(wxString(strVal));
|
|
|
|
// Get the version and bypass group if not found
|
|
if (!mConfig->Read(KEY_VERSION, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetVersion(wxString(strVal));
|
|
|
|
// Get the vendor and bypass group if not found
|
|
if (!mConfig->Read(KEY_VENDOR, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetVendor(wxString(strVal));
|
|
|
|
// Get the description and bypass group if not found
|
|
if (!mConfig->Read(KEY_DESCRIPTION, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetDescription(wxString(strVal));
|
|
|
|
// Is it enabled...default to no if not found
|
|
mConfig->Read(KEY_ENABLED, &boolVal, false);
|
|
plug.SetEnabled(boolVal);
|
|
|
|
// Is it valid...default to no if not found
|
|
mConfig->Read(KEY_VALID, &boolVal, false);
|
|
plug.SetValid(boolVal);
|
|
|
|
switch (type)
|
|
{
|
|
case PluginTypeModule:
|
|
{
|
|
// Nothing to do here yet
|
|
}
|
|
break;
|
|
|
|
case PluginTypeEffect:
|
|
{
|
|
// Get the effect type and bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTTYPE, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (strVal.IsSameAs(KEY_EFFECTTYPE_NONE))
|
|
{
|
|
plug.SetEffectType(EffectTypeNone);
|
|
}
|
|
else if (strVal.IsSameAs(KEY_EFFECTTYPE_ANALYZE))
|
|
{
|
|
plug.SetEffectType(EffectTypeAnalyze);
|
|
}
|
|
else if (strVal.IsSameAs(KEY_EFFECTTYPE_GENERATE))
|
|
{
|
|
plug.SetEffectType(EffectTypeGenerate);
|
|
}
|
|
else if (strVal.IsSameAs(KEY_EFFECTTYPE_PROCESS))
|
|
{
|
|
plug.SetEffectType(EffectTypeProcess);
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Get the effect family and bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTFAMILY, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetEffectFamily(wxString(strVal));
|
|
|
|
// Is it a default (above the line) effect and bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTDEFAULT, &boolVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetEffectDefault(boolVal);
|
|
|
|
// Is it an interactive effect and bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTINTERACTIVE, &boolVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetEffectInteractive(boolVal);
|
|
|
|
// Is it a realtime capable effect and bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTREALTIME, &boolVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetEffectRealtime(boolVal);
|
|
|
|
// Does the effect support automation...bypass group if not found
|
|
if (!mConfig->Read(KEY_EFFECTAUTOMATABLE, &boolVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetEffectAutomatable(boolVal);
|
|
}
|
|
break;
|
|
|
|
case PluginTypeImporter:
|
|
{
|
|
// Get the importer identifier and bypass group if not found
|
|
if (!mConfig->Read(KEY_IMPORTERIDENT, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetImporterIdentifier(wxString(strVal));
|
|
|
|
// Get the importer filter description and bypass group if not found
|
|
if (!mConfig->Read(KEY_IMPORTERFILTER, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
plug.SetImporterFilterDescription(wxString(strVal));
|
|
|
|
// Get the importer extensions and bypass group if not found
|
|
if (!mConfig->Read(KEY_IMPORTEREXTENSIONS, &strVal))
|
|
{
|
|
continue;
|
|
}
|
|
wxArrayString extensions;
|
|
wxStringTokenizer tkr(strVal, wxT(":"));
|
|
while (tkr.HasMoreTokens())
|
|
{
|
|
extensions.push_back(wxString(tkr.GetNextToken()));
|
|
}
|
|
plug.SetImporterExtensions(extensions);
|
|
}
|
|
break;
|
|
|
|
case PluginTypeNone:
|
|
{
|
|
// Used for placeholder groups
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Everything checked out...accept the plugin
|
|
mPlugins[groupName] = plug;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void PluginManager::Save()
|
|
{
|
|
// IF already closed THEN nothing to do.
|
|
if (mConfig == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: This is a bit drastic...only save groups when new plugins are registered
|
|
|
|
// Save the individual groups
|
|
SaveGroup(wxT("effects"), PluginTypeEffect);
|
|
SaveGroup(wxT("exporters"), PluginTypeExporter);
|
|
SaveGroup(wxT("importers"), PluginTypeImporter);
|
|
SaveGroup(wxT("placeholders"), PluginTypeNone);
|
|
|
|
// And now the providers
|
|
SaveGroup(wxT("modules"), PluginTypeModule);
|
|
|
|
mConfig->Flush();
|
|
}
|
|
|
|
void PluginManager::SaveGroup(const wxChar *group, PluginType type)
|
|
{
|
|
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
|
|
{
|
|
PluginDescriptor & plug = iter->second;
|
|
|
|
if (plug.GetPluginType() != type)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
mConfig->SetPath(CACHEROOT + group + wxCONFIG_PATH_SEPARATOR + ConvertID(plug.GetID()));
|
|
|
|
mConfig->Write(KEY_PATH, plug.GetPath());
|
|
mConfig->Write(KEY_NAME, plug.GetName());
|
|
mConfig->Write(KEY_VERSION, plug.GetVersion());
|
|
mConfig->Write(KEY_VENDOR, plug.GetVendor());
|
|
mConfig->Write(KEY_DESCRIPTION, plug.GetDescription());
|
|
mConfig->Write(KEY_PROVIDERID, plug.GetProviderID());
|
|
mConfig->Write(KEY_ENABLED, plug.IsEnabled());
|
|
mConfig->Write(KEY_VALID, plug.IsValid());
|
|
|
|
switch (type)
|
|
{
|
|
case PluginTypeModule:
|
|
break;
|
|
|
|
case PluginTypeEffect:
|
|
{
|
|
EffectType etype = plug.GetEffectType();
|
|
wxString stype;
|
|
if (etype == EffectTypeNone)
|
|
{
|
|
stype = KEY_EFFECTTYPE_NONE;
|
|
}
|
|
else if (etype == EffectTypeAnalyze)
|
|
{
|
|
stype = KEY_EFFECTTYPE_ANALYZE;
|
|
}
|
|
else if (etype == EffectTypeGenerate)
|
|
{
|
|
stype = KEY_EFFECTTYPE_GENERATE;
|
|
}
|
|
else if (etype == EffectTypeProcess)
|
|
{
|
|
stype = KEY_EFFECTTYPE_PROCESS;
|
|
}
|
|
mConfig->Write(KEY_EFFECTTYPE, stype);
|
|
mConfig->Write(KEY_EFFECTFAMILY, plug.GetEffectFamily());
|
|
mConfig->Write(KEY_EFFECTDEFAULT, plug.IsEffectDefault());
|
|
mConfig->Write(KEY_EFFECTINTERACTIVE, plug.IsEffectInteractive());
|
|
mConfig->Write(KEY_EFFECTREALTIME, plug.IsEffectRealtime());
|
|
mConfig->Write(KEY_EFFECTAUTOMATABLE, plug.IsEffectAutomatable());
|
|
}
|
|
break;
|
|
|
|
case PluginTypeImporter:
|
|
{
|
|
mConfig->Write(KEY_IMPORTERIDENT, plug.GetImporterIdentifier());
|
|
mConfig->Write(KEY_IMPORTERFILTER, plug.GetImporterFilterDescription());
|
|
const wxArrayString & extensions = plug.GetImporterExtensions();
|
|
wxString strExt;
|
|
for (size_t i = 0, cnt = extensions.size(); i < cnt; i++)
|
|
{
|
|
strExt += extensions[i] + wxT(":");
|
|
}
|
|
strExt.RemoveLast(1);
|
|
mConfig->Write(KEY_IMPORTEREXTENSIONS, strExt);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void PluginManager::CheckForUpdates(bool forceRescan)
|
|
{
|
|
// Get ModuleManager reference
|
|
ModuleManager & mm = ModuleManager::Get();
|
|
|
|
bool doRescan;
|
|
gPrefs->Read(wxT("/Plugins/Rescan"), &doRescan, true);
|
|
|
|
bool doCheck;
|
|
gPrefs->Read(wxT("/Plugins/CheckForUpdates"), &doCheck, true);
|
|
|
|
ProviderMap map;
|
|
|
|
// Always check for and disable missing plugins
|
|
//
|
|
// Since the user's saved presets are in the registery, never delete them. That is
|
|
// a job for the plugin manager UI (once it is written)
|
|
// Check for plugins that are no longer valid
|
|
PluginMap::iterator iter = mPlugins.begin();
|
|
while (iter != mPlugins.end())
|
|
{
|
|
PluginDescriptor & plug = iter->second;
|
|
const PluginID & plugID = plug.GetID();
|
|
const wxString & plugPath = plug.GetPath();
|
|
|
|
if (plug.GetPluginType() == PluginTypeModule)
|
|
{
|
|
if (!mm.IsProviderValid(plugID, plugPath))
|
|
{
|
|
plug.SetValid(false);
|
|
}
|
|
else
|
|
{
|
|
// Only collect plugin paths if we're doing a full scan or checking for updates
|
|
if (doRescan || doCheck)
|
|
{
|
|
wxArrayString paths = mm.FindPluginsForProvider(plugID, plugPath);
|
|
for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++)
|
|
{
|
|
map[paths[i]].Add(plugID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
plug.SetValid(mm.IsPluginValid(plug.GetProviderID(), plugID, plugPath));
|
|
}
|
|
|
|
iter++;
|
|
}
|
|
|
|
// If we're only checking for new plugins, then remove all of the known ones
|
|
if (doCheck && !doRescan)
|
|
{
|
|
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
|
|
{
|
|
PluginDescriptor & plug = iter->second;
|
|
const wxString & plugPath = plug.GetPath();
|
|
ProviderMap::iterator mapiter = map.find(plugPath);
|
|
if (mapiter != map.end())
|
|
{
|
|
map.erase(mapiter);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Allow the user to choose which ones to enable
|
|
if (map.size() != 0)
|
|
{
|
|
PluginRegistrationDialog dlg(map);
|
|
if (dlg.ShowModal() == wxID_OK)
|
|
{
|
|
gPrefs->Write(wxT("/Plugins/Rescan"), false);
|
|
}
|
|
}
|
|
|
|
if (mConfig)
|
|
{
|
|
Save();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int PluginManager::GetPluginCount(PluginType type)
|
|
{
|
|
int num = 0;
|
|
|
|
for (PluginMap::iterator iter = mPlugins.begin(); iter != mPlugins.end(); iter++)
|
|
{
|
|
if (iter->second.GetPluginType() == type)
|
|
{
|
|
num++;
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
const PluginDescriptor *PluginManager::GetPlugin(const PluginID & ID)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &mPlugins[ID];
|
|
}
|
|
|
|
const PluginDescriptor *PluginManager::GetFirstPlugin(PluginType type)
|
|
{
|
|
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
|
|
{
|
|
PluginDescriptor & plug = mPluginsIter->second;
|
|
bool familyEnabled = true;
|
|
if (type == PluginTypeEffect)
|
|
{
|
|
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
|
}
|
|
if (plug.IsValid() && plug.IsEnabled() && plug.GetPluginType() == type && familyEnabled)
|
|
{
|
|
return &mPluginsIter->second;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const PluginDescriptor *PluginManager::GetNextPlugin(PluginType type)
|
|
{
|
|
while (++mPluginsIter != mPlugins.end())
|
|
{
|
|
PluginDescriptor & plug = mPluginsIter->second;
|
|
bool familyEnabled = true;
|
|
if (type == PluginTypeEffect)
|
|
{
|
|
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
|
}
|
|
if (plug.IsValid() && plug.IsEnabled() && plug.GetPluginType() == type && familyEnabled)
|
|
{
|
|
return &mPluginsIter->second;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const PluginDescriptor *PluginManager::GetFirstPluginForEffectType(EffectType type)
|
|
{
|
|
for (mPluginsIter = mPlugins.begin(); mPluginsIter != mPlugins.end(); mPluginsIter++)
|
|
{
|
|
PluginDescriptor & plug = mPluginsIter->second;
|
|
bool familyEnabled;
|
|
if (type == PluginTypeEffect)
|
|
{
|
|
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
|
}
|
|
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
|
if (plug.IsValid() && plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
|
|
{
|
|
return &plug;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const PluginDescriptor *PluginManager::GetNextPluginForEffectType(EffectType type)
|
|
{
|
|
while (++mPluginsIter != mPlugins.end())
|
|
{
|
|
PluginDescriptor & plug = mPluginsIter->second;
|
|
bool familyEnabled;
|
|
gPrefs->Read(plug.GetEffectFamily() + wxT("/Enable"), &familyEnabled, true);
|
|
if (plug.IsValid() && plug.IsEnabled() && plug.GetEffectType() == type && familyEnabled)
|
|
{
|
|
return &plug;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
bool PluginManager::IsRegistered(const PluginID & ID)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const PluginID & PluginManager::RegisterLegacyEffectPlugin(EffectIdentInterface *effect)
|
|
{
|
|
PluginDescriptor & plug = CreatePlugin(effect, PluginTypeEffect);
|
|
|
|
plug.SetEffectType(effect->GetType());
|
|
plug.SetEffectFamily(effect->GetFamily());
|
|
plug.SetEffectInteractive(effect->IsInteractive());
|
|
plug.SetEffectDefault(effect->IsDefault());
|
|
plug.SetEffectRealtime(effect->SupportsRealtime());
|
|
plug.SetEffectAutomatable(effect->SupportsAutomation());
|
|
|
|
plug.SetInstance(effect);
|
|
plug.SetEffectLegacy(true);
|
|
plug.SetEnabled(true);
|
|
plug.SetValid(true);
|
|
|
|
return plug.GetID();
|
|
}
|
|
|
|
bool PluginManager::IsPluginEnabled(const PluginID & ID)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return mPlugins[ID].IsEnabled();
|
|
}
|
|
|
|
void PluginManager::EnablePlugin(const PluginID & ID, bool enable)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return;
|
|
}
|
|
|
|
return mPlugins[ID].SetEnabled(enable);
|
|
}
|
|
|
|
const wxString & PluginManager::GetName(const PluginID & ID)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
static wxString empty;
|
|
return empty;
|
|
}
|
|
|
|
return mPlugins[ID].GetName();
|
|
}
|
|
|
|
IdentInterface *PluginManager::GetInstance(const PluginID & ID)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
PluginDescriptor & plug = mPlugins[ID];
|
|
|
|
// If not dealing with legacy effects, make sure the provider is loaded
|
|
if (!plug.IsEffectLegacy())
|
|
{
|
|
const PluginID & prov = plug.GetProviderID();
|
|
if (mPlugins.find(prov) == mPlugins.end())
|
|
{
|
|
return NULL;
|
|
}
|
|
mPlugins[prov].GetInstance();
|
|
}
|
|
|
|
return plug.GetInstance();
|
|
}
|
|
|
|
// TODO: This goes away when all effects have been converted
|
|
void PluginManager::SetInstance(const PluginID & ID, IdentInterface *instance)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return;
|
|
}
|
|
|
|
return mPlugins[ID].SetInstance(instance);
|
|
}
|
|
|
|
PluginDescriptor & PluginManager::CreatePlugin(IdentInterface *ident, PluginType type)
|
|
{
|
|
// This will either create a new entry or replace an existing entry
|
|
PluginDescriptor & plug = mPlugins[ident->GetID()];
|
|
|
|
plug.SetPluginType(type);
|
|
|
|
plug.SetID(ident->GetID());
|
|
plug.SetPath(ident->GetPath());
|
|
plug.SetName(ident->GetName());
|
|
plug.SetVendor(ident->GetVendor());
|
|
plug.SetVersion(ident->GetVersion());
|
|
plug.SetDescription(ident->GetDescription());
|
|
|
|
return plug;
|
|
}
|
|
|
|
bool PluginManager::GetSubgroups(const wxString & group, wxArrayString & subgroups)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !group.IsEmpty())
|
|
{
|
|
wxString name = wxEmptyString;
|
|
long index = 0;
|
|
wxString path = mConfig->GetPath();
|
|
mConfig->SetPath(group);
|
|
|
|
if (mConfig->GetFirstGroup(name, index))
|
|
{
|
|
do
|
|
{
|
|
subgroups.Add(name);
|
|
} while (mConfig->GetNextGroup(name, index));
|
|
}
|
|
|
|
mConfig->SetPath(path);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, int & value, int defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Read(key, &value, defval);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, wxString & value, const wxString & defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
wxString wxval = wxEmptyString;
|
|
|
|
result = mConfig->Read(key, &wxval, defval);
|
|
|
|
value = wxval;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, bool & value, bool defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Read(key, &value, defval);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, float & value, float defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
double dval = 0.0;
|
|
|
|
result = mConfig->Read(key, &dval, (double) defval);
|
|
|
|
value = (float) dval;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, double & value, double defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Read(key, &value, defval);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::GetConfig(const wxString & key, sampleCount & value, sampleCount defval)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
wxString wxval = wxEmptyString;
|
|
wxString wxdef;
|
|
wchar_t *endptr;
|
|
wxdef.Printf(wxT("%Ld"), defval);
|
|
|
|
result = mConfig->Read(key, &wxval, wxdef);
|
|
value = wxStrtoll(wxval.c_str(), &endptr, 10);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const wxString & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
wxString wxval = value.c_str();
|
|
result = mConfig->Write(key, wxval);
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const int & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Write(key, value);
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const bool & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Write(key, value);
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const float & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Write(key, value);
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const double & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Write(key, value);
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool PluginManager::SetConfig(const wxString & key, const sampleCount & value)
|
|
{
|
|
bool result = false;
|
|
|
|
if (mConfig && !key.IsEmpty())
|
|
{
|
|
result = mConfig->Write(key, wxString::Format(wxT("%d"), (int) value));
|
|
if (result)
|
|
{
|
|
result = mConfig->Flush();
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
wxString PluginManager::SharedGroup(const PluginID & ID, const wxString & group)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return wxEmptyString;
|
|
}
|
|
|
|
wxString path = CACHEROOT +
|
|
ConvertID(mPlugins[ID].GetProviderID()) +
|
|
wxCONFIG_PATH_SEPARATOR +
|
|
wxT("shared") +
|
|
wxCONFIG_PATH_SEPARATOR;
|
|
|
|
wxFileName f(group);
|
|
if (!f.GetName().IsEmpty())
|
|
{
|
|
path += f.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
wxString PluginManager::SharedKey(const PluginID & ID, const wxString & group, const wxString & key)
|
|
{
|
|
wxString path = SharedGroup(ID, group);
|
|
if (path.IsEmpty())
|
|
{
|
|
return path;
|
|
}
|
|
|
|
return path + key;
|
|
}
|
|
|
|
wxString PluginManager::PrivateGroup(const PluginID & ID, const wxString & group)
|
|
{
|
|
if (mPlugins.find(ID) == mPlugins.end())
|
|
{
|
|
return wxEmptyString;
|
|
}
|
|
|
|
wxString path = CACHEROOT +
|
|
ConvertID(ID) +
|
|
wxCONFIG_PATH_SEPARATOR +
|
|
wxT("private") +
|
|
wxCONFIG_PATH_SEPARATOR;
|
|
|
|
wxFileName f(group);
|
|
if (!f.GetName().IsEmpty())
|
|
{
|
|
path += f.GetFullPath(wxPATH_UNIX) + wxCONFIG_PATH_SEPARATOR;
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
wxString PluginManager::PrivateKey(const PluginID & ID, const wxString & group, const wxString & key)
|
|
{
|
|
wxString path = PrivateGroup(ID, group);
|
|
if (path.IsEmpty())
|
|
{
|
|
return path;
|
|
}
|
|
|
|
return path + key;
|
|
}
|
|
|
|
// Sanitize the ID...not the best solution, but will suffice until this
|
|
// is converted to XML. We use base64 encoding to preserve case.
|
|
wxString PluginManager::ConvertID(const PluginID & ID)
|
|
{
|
|
if (ID.StartsWith(wxT("base64:")))
|
|
{
|
|
wxString id = ID.Mid(7);
|
|
char *buf = new char[id.Length() / 4 * 3];
|
|
id = wxString::FromUTF8(buf, b64decode(id, buf));
|
|
delete [] buf;
|
|
return id;
|
|
}
|
|
|
|
const wxCharBuffer & buf = ID.ToUTF8();
|
|
return wxT("base64:") + b64encode(buf, strlen(buf));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Base64 en/decoding
|
|
//
|
|
// Original routines marked as public domain and found at:
|
|
//
|
|
// http://en.wikibooks.org/wiki/Algorithm_implementation/Miscellaneous/Base64
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Lookup table for encoding
|
|
const static wxChar cset[] = wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
|
const static char padc = wxT('=');
|
|
|
|
wxString PluginManager::b64encode(const void *in, int len)
|
|
{
|
|
unsigned char *p = (unsigned char *) in;
|
|
wxString out;
|
|
|
|
unsigned long temp;
|
|
for (int i = 0; i < len / 3; i++)
|
|
{
|
|
temp = (*p++) << 16; //Convert to big endian
|
|
temp += (*p++) << 8;
|
|
temp += (*p++);
|
|
out += cset[(temp & 0x00FC0000) >> 18];
|
|
out += cset[(temp & 0x0003F000) >> 12];
|
|
out += cset[(temp & 0x00000FC0) >> 6];
|
|
out += cset[(temp & 0x0000003F)];
|
|
}
|
|
|
|
switch (len % 3)
|
|
{
|
|
case 1:
|
|
temp = (*p++) << 16; //Convert to big endian
|
|
out += cset[(temp & 0x00FC0000) >> 18];
|
|
out += cset[(temp & 0x0003F000) >> 12];
|
|
out += padc;
|
|
out += padc;
|
|
break;
|
|
|
|
case 2:
|
|
temp = (*p++) << 16; //Convert to big endian
|
|
temp += (*p++) << 8;
|
|
out += cset[(temp & 0x00FC0000) >> 18];
|
|
out += cset[(temp & 0x0003F000) >> 12];
|
|
out += cset[(temp & 0x00000FC0) >> 6];
|
|
out += padc;
|
|
break;
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
int PluginManager::b64decode(wxString in, void *out)
|
|
{
|
|
int len = in.length();
|
|
unsigned char *p = (unsigned char *) out;
|
|
|
|
if (len % 4) //Sanity check
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int padding = 0;
|
|
if (len)
|
|
{
|
|
if (in[len - 1] == padc)
|
|
{
|
|
padding++;
|
|
}
|
|
|
|
if (in[len - 2] == padc)
|
|
{
|
|
padding++;
|
|
}
|
|
}
|
|
|
|
//const char *a = in.mb_str();
|
|
//Setup a vector to hold the result
|
|
unsigned long temp = 0; //Holds decoded quanta
|
|
int i = 0;
|
|
while (i < len)
|
|
{
|
|
for (int quantumPosition = 0; quantumPosition < 4; quantumPosition++)
|
|
{
|
|
unsigned char c = in[i];
|
|
temp <<= 6;
|
|
|
|
if (c >= 0x41 && c <= 0x5A)
|
|
{
|
|
temp |= c - 0x41;
|
|
}
|
|
else if (c >= 0x61 && c <= 0x7A)
|
|
{
|
|
temp |= c - 0x47;
|
|
}
|
|
else if (c >= 0x30 && c <= 0x39)
|
|
{
|
|
temp |= c + 0x04;
|
|
}
|
|
else if (c == 0x2B)
|
|
{
|
|
temp |= 0x3E;
|
|
}
|
|
else if (c == 0x2F)
|
|
{
|
|
temp |= 0x3F;
|
|
}
|
|
else if (c == padc)
|
|
{
|
|
switch (len - i)
|
|
{
|
|
case 1: //One pad character
|
|
*p++ = (temp >> 16) & 0x000000FF;
|
|
*p++ = (temp >> 8) & 0x000000FF;
|
|
return p - (unsigned char *) out;
|
|
case 2: //Two pad characters
|
|
*p++ = (temp >> 10) & 0x000000FF;
|
|
return p - (unsigned char *) out;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
*p++ = (temp >> 16) & 0x000000FF;
|
|
*p++ = (temp >> 8) & 0x000000FF;
|
|
*p++ = temp & 0x000000FF;
|
|
}
|
|
|
|
return p - (unsigned char *) out;
|
|
}
|