Audacity 3.2.0
PluginRegistrationDialog.cpp
Go to the documentation of this file.
1/*!*********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file PluginRegistrationDialog.cpp
6
7 Paul Licameli split from PluginManager.cpp
8
9**********************************************************************/
11
12#include "EffectInterface.h"
13#include "ModuleManager.h"
14#include "PluginManager.h"
15#include "ShuttleGui.h"
18
19#include <wx/setup.h> // for wxUSE_* macros
20#include <wx/defs.h>
21#include <wx/dir.h>
22#include <wx/dynlib.h>
23#include <wx/filename.h>
24#include <wx/listctrl.h>
25#include <wx/radiobut.h>
26#include <wx/wfstream.h>
27#include <wx/utils.h>
28
29#define DISABLE_STATE_NEW
30
31// ============================================================================
32//
33//
34//
35// ============================================================================
36#if wxUSE_ACCESSIBILITY
38
39class CheckListAx final : public WindowAccessible
40{
41public:
42 CheckListAx(wxListCtrl * window);
43
44 virtual ~ CheckListAx();
45
46 // Retrieves the address of an IDispatch interface for the specified child.
47 // All objects must support this property.
48 wxAccStatus GetChild( int childId, wxAccessible **child ) override;
49
50 // Gets the number of children.
51 wxAccStatus GetChildCount( int *childCount ) override;
52
53 // Gets the default action for this object (0) or > 0 (the action for a child).
54 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
55 // string if there is no action.
56 // The retrieved string describes the action that is performed on an object,
57 // not what the object does as a result. For example, a toolbar button that prints
58 // a document has a default action of "Press" rather than "Prints the current document."
59 wxAccStatus GetDefaultAction( int childId, wxString *actionName ) override;
60
61 // Returns the description for this object or a child.
62 wxAccStatus GetDescription( int childId, wxString *description ) override;
63
64 // Gets the window with the keyboard focus.
65 // If childId is 0 and child is NULL, no object in
66 // this subhierarchy has the focus.
67 // If this object has the focus, child should be 'this'.
68 wxAccStatus GetFocus( int *childId, wxAccessible **child ) override;
69
70 // Returns help text for this object or a child, similar to tooltip text.
71 wxAccStatus GetHelpText( int childId, wxString *helpText ) override;
72
73 // Returns the keyboard shortcut for this object or child.
74 // Return e.g. ALT+K
75 wxAccStatus GetKeyboardShortcut( int childId, wxString *shortcut ) override;
76
77 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
78 // rect is in screen coordinates.
79 wxAccStatus GetLocation( wxRect& rect, int elementId ) override;
80
81 // Gets the name of the specified object.
82 wxAccStatus GetName( int childId, wxString *name ) override;
83
84 // Returns a role constant.
85 wxAccStatus GetRole( int childId, wxAccRole *role ) override;
86
87 // Gets a variant representing the selected children
88 // of this object.
89 // Acceptable values:
90 // - a null variant (IsNull() returns TRUE)
91 // - a list variant (GetType() == wxT("list"))
92 // - an integer representing the selected child element,
93 // or 0 if this object is selected (GetType() == wxT("long"))
94 // - a "void*" pointer to a wxAccessible child object
95 wxAccStatus GetSelections( wxVariant *selections ) override;
96
97 // Returns a state constant.
98 wxAccStatus GetState( int childId, long* state ) override;
99
100 // Returns a localized string representing the value for the object
101 // or child.
102 wxAccStatus GetValue( int childId, wxString *strValue ) override;
103
104 void SetSelected( int item, bool focused = true );
105
106private:
107 wxListCtrl *mParent;
108 int mLastId;
109};
110
111CheckListAx::CheckListAx( wxListCtrl * window )
112: WindowAccessible( window )
113{
114 mParent = window;
115 mLastId = -1;
116}
117
118CheckListAx::~CheckListAx()
119{
120}
121
122void CheckListAx::SetSelected( int item, bool focused )
123{
124 if (mLastId != -1)
125 {
126 NotifyEvent( wxACC_EVENT_OBJECT_SELECTIONREMOVE,
127 mParent,
128 wxOBJID_CLIENT,
129 mLastId );
130 mLastId = -1;
131 }
132
133 if (item != -1)
134 {
135 if (focused)
136 {
137 NotifyEvent( wxACC_EVENT_OBJECT_FOCUS,
138 mParent,
139 wxOBJID_CLIENT,
140 item + 1 );
141 }
142
143 NotifyEvent( wxACC_EVENT_OBJECT_SELECTION,
144 mParent,
145 wxOBJID_CLIENT,
146 item + 1 );
147
148 mLastId = item + 1;
149 }
150}
151
152// Retrieves the address of an IDispatch interface for the specified child.
153// All objects must support this property.
154wxAccStatus CheckListAx::GetChild( int childId, wxAccessible** child )
155{
156 if( childId == wxACC_SELF )
157 {
158 *child = this;
159 }
160 else
161 {
162 *child = NULL;
163 }
164
165 return wxACC_OK;
166}
167
168// Gets the number of children.
169wxAccStatus CheckListAx::GetChildCount( int *childCount )
170{
171 *childCount = mParent->GetItemCount();
172
173 return wxACC_OK;
174}
175
176// Gets the default action for this object (0) or > 0 (the action for a child).
177// Return wxACC_OK even if there is no action. actionName is the action, or the empty
178// string if there is no action.
179// The retrieved string describes the action that is performed on an object,
180// not what the object does as a result. For example, a toolbar button that prints
181// a document has a default action of "Press" rather than "Prints the current document."
182wxAccStatus CheckListAx::GetDefaultAction( int WXUNUSED(childId), wxString *actionName )
183{
184 actionName->clear();
185
186 return wxACC_OK;
187}
188
189// Returns the description for this object or a child.
190wxAccStatus CheckListAx::GetDescription( int WXUNUSED(childId), wxString *description )
191{
192 description->clear();
193
194 return wxACC_OK;
195}
196
197// Gets the window with the keyboard focus.
198// If childId is 0 and child is NULL, no object in
199// this subhierarchy has the focus.
200// If this object has the focus, child should be 'this'.
201wxAccStatus CheckListAx::GetFocus( int *childId, wxAccessible **child )
202{
203 *childId = 0;
204 *child = this;
205
206 return wxACC_OK;
207}
208
209// Returns help text for this object or a child, similar to tooltip text.
210wxAccStatus CheckListAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
211{
212 helpText->clear();
213
214 return wxACC_OK;
215}
216
217// Returns the keyboard shortcut for this object or child.
218// Return e.g. ALT+K
219wxAccStatus CheckListAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
220{
221 shortcut->clear();
222
223 return wxACC_OK;
224}
225
226// Returns the rectangle for this object (id = 0) or a child element (id > 0).
227// rect is in screen coordinates.
228wxAccStatus CheckListAx::GetLocation( wxRect& rect, int elementId )
229{
230 if( elementId == wxACC_SELF )
231 {
232 rect = mParent->GetRect();
233 rect.SetPosition( mParent->GetParent()->ClientToScreen( rect.GetPosition() ) );
234 }
235 else
236 {
237 if( elementId <= mParent->GetItemCount() )
238 {
239 mParent->GetItemRect( elementId - 1, rect, wxLIST_RECT_LABEL );
240 rect.SetPosition( mParent->ClientToScreen( rect.GetPosition() ) );
241 }
242 }
243
244 return wxACC_OK;
245}
246
247// Gets the name of the specified object.
248wxAccStatus CheckListAx::GetName( int WXUNUSED(childId), wxString *name )
249{
250 *name = mParent->GetName();
251
252 return wxACC_OK;
253}
254
255// Returns a role constant.
256wxAccStatus CheckListAx::GetRole( int childId, wxAccRole *role )
257{
258 if( childId == wxACC_SELF )
259 {
260 *role = wxROLE_SYSTEM_LIST;
261 }
262 else
263 {
264 *role = wxROLE_SYSTEM_LISTITEM;
265 }
266
267 return wxACC_OK;
268}
269
270// Gets a variant representing the selected children
271// of this object.
272// Acceptable values:
273// - a null variant (IsNull() returns TRUE)
274// - a list variant (GetType() == wxT("list"))
275// - an integer representing the selected child element,
276// or 0 if this object is selected (GetType() == wxT("long"))
277// - a "void*" pointer to a wxAccessible child object
278wxAccStatus CheckListAx::GetSelections( wxVariant * WXUNUSED(selections) )
279{
280 return wxACC_NOT_IMPLEMENTED;
281}
282
283// Returns a state constant.
284wxAccStatus CheckListAx::GetState( int childId, long *pState )
285{
286 int flag = wxACC_STATE_SYSTEM_FOCUSABLE;
287
288 if( childId == wxACC_SELF )
289 {
290 flag |= wxACC_STATE_SYSTEM_FOCUSED;
291 }
292 else
293 {
294 wxListItem item;
295
296 item.SetId( childId - 1 );
297 item.SetState( wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED );
298 item.SetMask( wxLIST_MASK_STATE );
299
300 if( mParent->GetItem( item ) )
301 {
302 flag |= wxACC_STATE_SYSTEM_SELECTABLE;
303
304 long state = item.GetState();
305
306 if( state & wxLIST_STATE_FOCUSED )
307 {
308 flag |= wxACC_STATE_SYSTEM_FOCUSED;
309 }
310
311 if( state & wxLIST_STATE_SELECTED )
312 {
313 flag |= wxACC_STATE_SYSTEM_SELECTED;
314 }
315 }
316 }
317
318 *pState = flag;
319
320 return wxACC_OK;
321}
322
323// Returns a localized string representing the value for the object
324// or child.
325wxAccStatus CheckListAx::GetValue( int childId, wxString *strValue )
326{
327 if( childId == 0 )
328 {
329 return wxACC_OK;
330 }
331 else
332 {
333 *strValue = mParent->GetItemText( childId - 1 );
334 }
335
336 return wxACC_OK;
337}
338
339#endif
340enum
341{
344#ifndef DISABLE_STATE_NEW
345 STATE_New,
346#endif
347
350
351enum
352{
353 ID_ShowAll = 10000,
356#ifndef DISABLE_STATE_NEW
357 ID_ShowNew,
358#endif
364};
365
366enum
367{
371
374
376 EVT_LIST_COL_CLICK(ID_List, PluginRegistrationDialog::OnSort)
386#ifndef DISABLE_STATE_NEW
387 EVT_RADIOBUTTON(ID_ShowNew, PluginRegistrationDialog::OnChangedVisibility)
388#endif
390
392: wxDialogWrapper(parent,
393 wxID_ANY,
394 XO("Manage Plug-ins"),
395 wxDefaultPosition, wxDefaultSize,
396 wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
397{
398 mEffects = NULL;
399 SetName();
400
401 mStates.resize(STATE_COUNT);
402 mStates[STATE_Enabled] = _("Enabled");
403 mStates[STATE_Disabled] = _("Disabled");
404#ifndef DISABLE_STATE_NEW
405 mStates[STATE_New] = _("New");
406#endif
407
408 mSortColumn = COL_Name;
409 mSortDirection = 1;
410
411 Populate();
412
413 DoSort( mSortColumn );
414}
415
417{
418 //------------------------- Main section --------------------
419 ShuttleGui S(this, eIsCreating);
421 // ----------------------- End of main section --------------
422}
423
426{
427 S.StartVerticalLay(true);
428 {
429 /*i18n-hint: The dialog shows a list of plugins with check-boxes
430 beside each one.*/
431// S.StartStatic(XO("Effects"), true);
432 S.StartVerticalLay();
433 {
434 S.StartHorizontalLay(wxEXPAND, 0);
435 {
436 S.StartHorizontalLay(wxALIGN_LEFT, 0);
437 {
438 S.AddPrompt(XXO("Select effects, click the Enable or Disable button, then click OK."));
439 }
440 S.EndHorizontalLay();
441
442 S.StartHorizontalLay(wxCENTER, 1);
443 {
444 S.AddSpace(1);
445 }
446 S.EndHorizontalLay();
447
448 S.StartHorizontalLay(wxALIGN_NOT | wxALIGN_LEFT, 0);
449 {
450 wxRadioButton *rb;
451
452 /* i18n-hint: This is before radio buttons selecting which effects to show */
453 S.AddPrompt(XXO("Show:"));
454 rb = S.Id(ID_ShowAll)
455 /* i18n-hint: Radio button to show all effects */
456 .Name(XO("Show all"))
457 /* i18n-hint: Radio button to show all effects */
458 .AddRadioButton(XXO("&All"));
459#if wxUSE_ACCESSIBILITY
460 // so that name can be set on a standard control
461 rb->SetAccessible(safenew WindowAccessible(rb));
462#endif
463
464 rb = S.Id(ID_ShowDisabled)
465 /* i18n-hint: Radio button to show just the currently disabled effects */
466 .Name(XO("Show disabled"))
467 /* i18n-hint: Radio button to show just the currently disabled effects */
468 .AddRadioButtonToGroup(XXO("D&isabled"));
469#if wxUSE_ACCESSIBILITY
470 // so that name can be set on a standard control
471 rb->SetAccessible(safenew WindowAccessible(rb));
472#endif
473
474 rb = S.Id(ID_ShowEnabled)
475 /* i18n-hint: Radio button to show just the currently enabled effects */
476 .Name(XO("Show enabled"))
477 /* i18n-hint: Radio button to show just the currently enabled effects */
478 .AddRadioButtonToGroup(XXO("E&nabled"));
479#if wxUSE_ACCESSIBILITY
480 // so that name can be set on a standard control
481 rb->SetAccessible(safenew WindowAccessible(rb));
482#endif
483
484#ifndef DISABLE_STATE_NEW
485 rb = S.Id(ID_ShowNew)
486 /* i18n-hint: Radio button to show just the newly discovered effects */
487 .Name(XO("Show new"))
488 /* i18n-hint: Radio button to show just the newly discovered effects */
489 .AddRadioButtonToGroup(XXO("Ne&w"));
490#if wxUSE_ACCESSIBILITY
491 // so that name can be set on a standard control
492 rb->SetAccessible(safenew WindowAccessible(rb));
493#endif
494#endif
495 }
496 S.EndHorizontalLay();
497 }
498 S.EndHorizontalLay();
499
500 mEffects = S.Id(ID_List)
501 .Style(wxSUNKEN_BORDER | wxLC_REPORT | wxLC_HRULES | wxLC_VRULES )
502 .ConnectRoot(wxEVT_KEY_DOWN,
504 .AddListControlReportMode({ XO("Name"), XO("State"), XO("Path") });
505#if wxUSE_ACCESSIBILITY
506 mEffects->SetAccessible(mAx = safenew CheckListAx(mEffects));
507#endif
508
509 S.StartHorizontalLay(wxALIGN_LEFT | wxEXPAND, 0);
510 {
511 S.Id(ID_SelectAll).AddButton(XXO("&Select All"));
512 S.Id(ID_ClearAll).AddButton(XXO("C&lear All"));
513
514 S.StartHorizontalLay(wxALIGN_CENTER);
515 {
516 S.AddSpace(1);
517 }
518 S.EndHorizontalLay();
519
520 S.Id(ID_Enable).AddButton(XXO("&Enable"));
521 S.Id(ID_Disable).AddButton(XXO("&Disable"));
522 }
523 S.EndHorizontalLay();
524 }
525// S.EndStatic();
526 S.EndVerticalLay();
527
528 S.AddStandardButtons(eOkButton | eCancelButton);
529 }
530 S.EndVerticalLay();
531
532 std::vector<int> colWidths;
533 for (int i = 0, cnt = mEffects->GetColumnCount(); i < cnt; i++)
534 {
535 colWidths.push_back(0);
536 }
537
538 for (int i = 0, cnt = mStates.size(); i < cnt; i++)
539 {
540 int x;
541 mEffects->GetTextExtent(mStates[i], &x, NULL);
542 colWidths[COL_State] = wxMax(colWidths[COL_State], x + 4); // 2 pixel margin on each side
543 }
544
546 for (auto &plug : pm.AllPlugins()) {
547 PluginType plugType = plug.GetPluginType();
548 if (plugType != PluginTypeEffect && plugType != PluginTypeStub)
549 continue;
550
551 const auto &path = plug.GetPath();
552 ItemData & item = mItems[path]; // will create NEW entry
553 item.plugs.push_back(&plug);
554 item.path = path;
555 item.state = plug.IsEnabled() ? STATE_Enabled : STATE_Disabled;
556 item.valid = plug.IsValid();
557
558 if (plugType == PluginTypeEffect)
559 {
560 item.name = plug.GetSymbol().Translation();
561 }
562 // This is not right and will not work when other plugin types are added.
563 // But it's presumed that the plugin manager dialog will be fully developed
564 // by then.
565 else if (plugType == PluginTypeStub)
566 {
567 wxFileName fname { path };
568 item.name = fname.GetName().Trim(false).Trim(true);
569#ifndef DISABLE_STATE_NEW
570 if (!item.valid)
571 {
572 item.state = STATE_New;
573 }
574#endif
575 }
576
577 int x;
578 mEffects->GetTextExtent(item.name, &x, NULL);
579 colWidths[COL_Name] = wxMax(colWidths[COL_Name], x);
580
581 mEffects->GetTextExtent(item.path, &x, NULL);
582 if (x > colWidths[COL_Path])
583 {
584 mLongestPath = item.path;
585 }
586 colWidths[COL_Path] = wxMax(colWidths[COL_Path], x);
587 }
588
589 wxRect r = wxGetClientDisplayRect();
590
591 int maxW = 0;
592 for (int i = 0, cnt = mEffects->GetColumnCount(); i < cnt; i++)
593 {
594 int w = colWidths[i] + /* fudge */ 10;
595 mEffects->SetColumnWidth(i, w);
596 maxW += w;
597 }
598
599 // Keep dialog from getting too wide
600 int w = r.GetWidth() - (GetClientSize().GetWidth() - mEffects->GetSize().GetWidth());
601 mEffects->SetMinSize({ std::min(maxW, w), 200 });
602 mEffects->SetMaxSize({ w, -1 });
603
605
606 Layout();
607 Fit();
608
609 wxSize sz = GetSize();
610 sz.SetWidth(wxMin(sz.GetWidth(), r.GetWidth()));
611 sz.SetHeight(wxMin(sz.GetHeight(), r.GetHeight()));
612 SetMinSize(sz);
613
614 // Parent window is usually not there yet, so centre on screen rather than on parent.
615 CenterOnScreen();
616
617 if (mEffects->GetItemCount() > 0)
618 {
619 // Make sure first item is selected/focused.
620 mEffects->SetFocus();
621 mEffects->SetItemState(0, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED | wxLIST_STATE_SELECTED);
622#if wxUSE_ACCESSIBILITY
623 mAx->SetSelected(0);
624#endif
625 }
626
627}
628
630{
631 mFilter = filter;
632
633 mEffects->DeleteAllItems();
634
635 int i = 0;
636 for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter)
637 {
638 ItemData & item = iter->second;
639 bool add = false;
640
641 switch (mFilter)
642 {
643 case ID_ShowAll:
644 add = true;
645 break;
646#ifndef DISABLE_STATE_NEW
647 case ID_ShowNew:
648 if (item.state == STATE_New)
649 {
650 add = true;
651 }
652 break;
653#endif
654 case ID_ShowEnabled:
655 if (item.state == STATE_Enabled)
656 {
657 add = true;
658 }
659 break;
660 case ID_ShowDisabled:
661 if (item.state == STATE_Disabled)
662 {
663 add = true;
664 }
665 break;
666 }
667
668 if (add)
669 {
670 mEffects->InsertItem(i, item.name);
671 mEffects->SetItem(i, COL_State, mStates[item.state]);
672 mEffects->SetItem(i, COL_Path, item.path);
673 mEffects->SetItemPtrData(i, (wxUIntPtr) &item);
674
675 ++i;
676 }
677 }
678
679 mEffects->SortItems(SortCompare, (wxUIntPtr) this);
680
681 if (mEffects->GetItemCount() > 0)
682 {
683 // Make sure first item is selected/focused.
684// mEffects->SetFocus();
685 mEffects->SetItemState(0, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED, wxLIST_STATE_FOCUSED|wxLIST_STATE_SELECTED);
686#if wxUSE_ACCESSIBILITY
687 mAx->SetSelected(0, false);
688#endif
689 }
690}
691
692void PluginRegistrationDialog::SetState(int i, bool toggle, bool state)
693{
694 wxListItem li;
695
696 li.m_mask = wxLIST_MASK_DATA;
697 li.m_itemId = i;
698
699 mEffects->GetItem(li);
700
701 ItemData *item = (ItemData *) li.m_data;
702
703#ifndef DISABLE_STATE_NEW
704 // If changing the state of a "New" (stub) entry, then we mark it as valid
705 // since it will either be registered if "Enabled" or ignored if "Disabled".
706 if (item->state == STATE_New)
707 {
708 item->valid = true;
709 }
710#endif
711
712 if (toggle)
713 {
715 }
716 else
717 {
718 item->state = state;
719 }
720
721#ifndef DISABLE_STATE_NEW
722 if (mFilter == ID_ShowNew && item->state != STATE_New)
723 {
724 mEffects->DeleteItem(i);
725 }
726 else//if
727#endif
728 if (mFilter == ID_ShowDisabled && item->state != STATE_Disabled)
729 {
730 mEffects->DeleteItem(i);
731 }
732 else if (mFilter == ID_ShowEnabled && item->state != STATE_Enabled)
733 {
734 mEffects->DeleteItem(i);
735 }
736 else
737 {
738 mEffects->SetItem(i, COL_State, mStates[item->state]);
739#if wxUSE_ACCESSIBILITY
740 mAx->SetSelected(i);
741#endif
742 }
743}
744
745int wxCALLBACK PluginRegistrationDialog::SortCompare(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
746{
748 ItemData *i1 = (ItemData *) item1;
749 ItemData *i2 = (ItemData *) item2;
750
751 return dlg->SortCompare(i1, i2);
752}
753
755{
756 // This function is a three-valued comparator
757
758 wxString *str1;
759 wxString *str2;
760
761 switch (mSortColumn)
762 {
763 case COL_Name:
764 str1 = &item1->name;
765 str2 = &item2->name;
766 break;
767 case COL_State:
768 str1 = &mStates[item1->state];
769 str2 = &mStates[item2->state];
770 break;
771 case COL_Path:
772 str1 = &item1->path;
773 str2 = &item2->path;
774 break;
775 default:
776 return 0;
777 }
778
779 return str2->CmpNoCase(*str1) * mSortDirection;
780}
781
783{
784 // Go and show the relevant items.
785 RegenerateEffectsList(evt.GetId());
786}
787
788void PluginRegistrationDialog::OnSort(wxListEvent & evt)
789{
790 int col = evt.GetColumn();
791 DoSort( col );
792}
793
795{
796 if (col != mSortColumn)
797 {
798 mSortDirection = 1;
799 }
800 else
801 {
802 mSortDirection *= -1;
803 }
804
805 mSortColumn = col;
806 mEffects->SortItems(SortCompare, (wxUIntPtr) this);
807
808 // Without a refresh, wxMac doesn't redisplay the list properly after a sort
809 mEffects->Refresh();
810}
811
813{
814 switch (evt.GetKeyCode())
815 {
816 case WXK_SPACE:
817 {
818 int item = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_FOCUSED);
819 if (item != wxNOT_FOUND)
820 {
821 SetState(item, true);
822 }
823 }
824 break;
825
826 case WXK_RETURN:
827 // Don't know why wxListCtrls prevent default dialog action,
828 // but they do, so handle it.
829 EmulateButtonClickIfPresent(GetAffirmativeId());
830 break;
831
832 default:
833 evt.Skip();
834 break;
835 }
836}
837
838void PluginRegistrationDialog::OnSelectAll(wxCommandEvent & WXUNUSED(evt))
839{
840 for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++)
841 {
842 mEffects->SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
843 }
844}
845
846void PluginRegistrationDialog::OnClearAll(wxCommandEvent & WXUNUSED(evt))
847{
848 for (int i = 0, cnt = mEffects->GetItemCount(); i < cnt; i++)
849 {
850 mEffects->SetItemState(i, 0, wxLIST_STATE_SELECTED);
851 }
852}
853
854void PluginRegistrationDialog::OnEnable(wxCommandEvent & WXUNUSED(evt))
855{
856 std::vector<long> items;
857
858 {
859 long i = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
860 while (i != wxNOT_FOUND)
861 {
862 items.insert(items.begin(), i);
863 i = mEffects->GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
864 }
865 }
866
867 for (size_t i = 0, cnt = items.size(); i < cnt; i++)
868 {
869 SetState(items[i], false, STATE_Enabled);
870 }
871}
872
873void PluginRegistrationDialog::OnDisable(wxCommandEvent & WXUNUSED(evt))
874{
875 std::vector<long> items;
876
877 {
878 long i = mEffects->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
879 while (i != wxNOT_FOUND)
880 {
881 items.insert(items.begin(), i);
882 i = mEffects->GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
883 }
884 }
885
886 for (size_t i = 0, cnt = items.size(); i < cnt; i++)
887 {
888 SetState(items[i], false, STATE_Disabled);
889 }
890}
891
892void PluginRegistrationDialog::OnOK(wxCommandEvent & WXUNUSED(evt))
893{
896
897 int enableCount = 0;
898 for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter)
899 {
900 ItemData & item = iter->second;
901 wxString path = item.path;
902
903 if (item.state == STATE_Enabled && item.plugs[0]->GetPluginType() == PluginTypeStub)
904 {
905 enableCount++;
906 }
907 }
908
909 wxString last3 = mLongestPath + wxT("\n") +
910 mLongestPath + wxT("\n") +
911 mLongestPath + wxT("\n");
912
913 auto msg = XO("Enabling effects or commands:\n\n%s").Format( last3 );
914
915 // Make sure the progress dialog is deleted before we call EndModal() or
916 // we will leave the project window in an unusable state on OSX.
917 // See bug #1192.
918 {
919 ProgressDialog progress{
920 Verbatim( GetTitle() ), msg, pdlgHideStopButton };
921 progress.CenterOnParent();
922
923 int i = 0;
924 for (ItemDataMap::iterator iter = mItems.begin(); iter != mItems.end(); ++iter)
925 {
926 ItemData & item = iter->second;
927 wxString path = item.path;
928
929 if (item.state == STATE_Enabled && item.plugs[0]->GetPluginType() == PluginTypeStub)
930 {
931 last3 = last3.AfterFirst(wxT('\n')) + item.path + wxT("\n");
932 auto status = progress.Update(++i, enableCount,
933 XO("Enabling effect or command:\n\n%s").Format( last3 ));
934 if (status == ProgressResult::Cancelled)
935 {
936 break;
937 }
938
939 TranslatableString errMsgs;
940
941 // Try to register the plugin via each provider until one succeeds
942 for (size_t j = 0, cntj = item.plugs.size(); j < cntj; j++)
943 {
944 TranslatableString errMsg;
945 if (mm.RegisterEffectPlugin(item.plugs[j]->GetProviderID(), path,
946 errMsg))
947 {
948 for (auto plug : item.plugs)
950 plug->GetProviderID() + wxT("_") + path);
951 // Bug 1893. We've found a provider that works.
952 // Error messages from any that failed are no longer useful.
953 errMsgs = {};
954 break;
955 }
956 else
957 {
958 if (!errMsgs.empty())
959 errMsgs.Join( errMsg, '\n' );
960 else
961 errMsgs = errMsg;
962 }
963 }
964 if (!errMsgs.empty())
966 XO("Effect or Command at %s failed to register:\n%s")
967 .Format( path, errMsgs ) );
968 }
969#ifndef DISABLE_STATE_NEW
970 else if (item.state == STATE_New) {
971 for (auto plug : item.plugs)
972 plug->SetValid(false);
973 }
974#endif
975 else {
976 for (auto plug : item.plugs) {
977 plug->SetEnabled(item.state == STATE_Enabled);
978 plug->SetValid(item.valid);
979 }
980 }
981 }
982
983 pm.Save();
984 }
985
986 EndModal(wxID_OK);
987}
988
989void PluginRegistrationDialog::OnCancel(wxCommandEvent & WXUNUSED(evt))
990{
991 EndModal(wxID_CANCEL);
992}
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
END_EVENT_TABLE()
int min(int a, int b)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:82
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define _(s)
Definition: Internat.h:75
#define safenew
Definition: MemoryX.h:10
PluginType
@ PluginTypeStub
@ PluginTypeEffect
#define DISABLE_STATE_NEW
@ pdlgHideStopButton
@ eIsCreating
Definition: ShuttleGui.h:39
@ eOkButton
Definition: ShuttleGui.h:597
@ eCancelButton
Definition: ShuttleGui.h:598
#define S(N)
Definition: ToChars.cpp:64
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
static std::once_flag flag
Abstract base class used in importing a file.
static ModuleManager & Get()
bool RegisterEffectPlugin(const PluginID &provider, const PluginPath &path, TranslatableString &errMsg)
PluginManager maintains a list of all plug ins. That covers modules, effects, generators,...
Definition: PluginManager.h:41
void Save()
Save to preferences.
void UnregisterPlugin(const PluginID &ID)
Range AllPlugins()
static PluginManager & Get()
void PopulateOrExchange(ShuttleGui &S)
Defines the dialog and does data exchange with it.
void OnClearAll(wxCommandEvent &evt)
void OnDisable(wxCommandEvent &evt)
void SetState(int i, bool toggle, bool state=true)
void OnCancel(wxCommandEvent &evt)
static int wxCALLBACK SortCompare(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData)
void RegenerateEffectsList(int iShowWhat)
void OnChangedVisibility(wxCommandEvent &evt)
void OnOK(wxCommandEvent &evt)
void OnEnable(wxCommandEvent &evt)
void OnSelectAll(wxCommandEvent &evt)
ProgressDialog Class.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
Holds a msgid for the translation catalog; may also bind format arguments.
TranslatableString & Join(TranslatableString arg, const wxString &separator={}) &
Append another translatable string.
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
std::vector< PluginDescriptor * > plugs