Audacity 3.2.0
PluginDataModel.cpp
Go to the documentation of this file.
1
2/*!*********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 @file PluginDataModel.cpp
7 @author Vitaly Sverchinsky
8
9**********************************************************************/
10
11#include "PluginDataModel.h"
12
13#include "ModuleManager.h"
14#include "PluginManager.h"
15
16const void* PluginDataModel::RowIdRoot {};
17
19{
20 void* data;
21 uint32_t value;
22};
23
24uint32_t GetRowIndex(const wxDataViewItem& item)
25{
26 const RowConv conv { item.GetID() };
27 return conv.value & 0x7FFFFFFF;
28}
29
30void* MakeRow(uint32_t index)
31{
32 RowConv conv { nullptr };
33 conv.value = index | 0x80000000;
34 return conv.data;
35}
36
37PluginDataModel::PluginDataModel(int filterEffectCategory,
38 int filterState,
39 const wxString& filterType,
40 const wxString& filterExpr)
41 : mFilterType(filterType)
42 , mFilterExpr(filterExpr)
43 , mFilterState(filterState)
44 , mFilterCategory(filterEffectCategory)
45{
46 auto& pm = PluginManager::Get();
47 for(auto& desc : pm.AllPlugins())
48 {
49 if ((desc.GetPluginType() != PluginTypeEffect || desc.GetEffectType() == EffectTypeHidden) &&
50 desc.GetPluginType() != PluginTypeStub)
51 {
52 continue;
53 }
54 mPluginStateModel.emplace_back(&desc, desc.IsEnabled());
55 }
57}
58
59wxDataViewItem PluginDataModel::GetItemForRow(uint32_t row) const
60{
61 if(row < mIndexFilterMap.size())
62 return wxDataViewItem { mIndexFilterMap[row] };
63 return {};
64}
65
66bool PluginDataModel::GetRowForItem(const wxDataViewItem& item, uint32_t& row) const
67{
68 if(item.IsOk())
69 {
70 row = GetRowIndex(item);
71 return row < mIndexFilterMap.size();
72 }
73 return false;
74}
75
77{
78 return mIndexFilterMap.size();
79}
80
81bool PluginDataModel::IsEnabled(const wxDataViewItem& item, unsigned col) const
82{
83 return true;
84}
85
86bool PluginDataModel::HasContainerColumns(const wxDataViewItem& item) const
87{
88 return item.GetID() == RowIdRoot;
89}
90
91void PluginDataModel::SetFilterType(const wxString& type)
92{
93 if(mFilterType != type)
94 {
95 mFilterType = type;
97 }
98}
99
101{
102 return mFilterType;
103}
104
106{
107 if(mFilterState != state)
108 {
109 mFilterState = state;
110 UpdateFilter();
111 }
112}
113
115{
116 return mFilterState;
117}
118
119void PluginDataModel::SetFilterExpr(const wxString& expr)
120{
121 if(mFilterExpr != expr)
122 {
123 mFilterExpr = expr;
124 UpdateFilter();
125 }
126}
127
129{
130 return mFilterExpr;
131}
132
134{
135 if(mFilterCategory != category)
136 {
137 mFilterCategory = category;
138 UpdateFilter();
139 }
140}
141
143{
144 return mFilterCategory;
145}
146
147int PluginDataModel::Compare(const wxDataViewItem& item1, const wxDataViewItem& item2, unsigned column,
148 bool ascending) const
149{
150 switch(column)
151 {
152 case ColumnName:
153 case ColumnPath:
154 case ColumnType:
155 {
156 wxVariant value1;
157 GetValue(value1, item1, column);
158 wxVariant value2;
159 GetValue(value2, item2, column);
160 const auto result = value1.GetString().CmpNoCase(value2.GetString());
161 //Prevent row "jumping" when strings are equal
162 if(result == 0)
163 return ascending == wxPtrToUInt(item1.GetID()) > wxPtrToUInt(item2.GetID()) ? 1 : -1;
164 return ascending ? result : -result;
165 } break;
166 default:
167 return wxDataViewModel::Compare(item1, item2, column, ascending);
168 }
169}
170
171void PluginDataModel::ApplyChanges(const std::function<bool(int, int, const wxString&)>& progressUpdateFn,
172 const std::function<void(const TranslatableString&)>& errorFn)
173{
174 auto& mm = ModuleManager::Get();
175 auto& pm = PluginManager::Get();
176
177 const auto enableCount = std::count_if(
178 mPluginStateModel.begin(),
179 mPluginStateModel.end(),
180 [](const auto& p) { return p.first->GetPluginType() == PluginTypeStub && p.second; }
181 );
182
183 auto counter = 0;
184 for(const auto& [desc, enabled] : mPluginStateModel)
185 {
186 if(desc->GetPluginType() == PluginTypeStub && enabled)
187 {
188 if(progressUpdateFn)
189 {
190 if(!progressUpdateFn(++counter, enableCount, desc->GetPath()))
191 break;
192 }
193
194 TranslatableString errMsg;
195 if (mm.RegisterEffectPlugin(desc->GetProviderID(), desc->GetPath(), errMsg))
196 pm.UnregisterPlugin(desc->GetProviderID() + wxT("_") + desc->GetPath());
197 else if (errorFn)
198 {
199 errorFn(XO("Effect or Command at %s failed to register:\n%s")
200 .Format( desc->GetPath(), !errMsg.empty() ? errMsg : XO("Unknown error") ));
201 }
202 }
203 else
204 desc->SetEnabled(enabled);
205 }
206 pm.Save();
207 pm.NotifyPluginsChanged();
208}
209
211{
212 return 4;
213}
214
215wxString PluginDataModel::GetColumnType(unsigned col) const
216{
217 switch(col)
218 {
219 case ColumnName:
220 case ColumnType:
221 case ColumnPath:
222 return "string";
223 case ColumnState:
224 return "bool";
225 default: break;
226 }
227 return "null";
228}
229
230void PluginDataModel::GetValue(wxVariant& variant, const wxDataViewItem& item, unsigned col) const
231{
232 assert(item.IsOk());
233
234 const auto index = GetRowIndex(item);
235 if(index >= mPluginStateModel.size())
236 return;
237
238 const auto [descriptor, state] = mPluginStateModel[index];
239 switch(col)
240 {
241 case ColumnName:
242 {
243 if (descriptor->GetPluginType() == PluginTypeEffect)
244 variant = descriptor->GetSymbol().Translation();
245 // This is not right and will not work when other plugin types are added.
246 // But it's presumed that the plugin manager dialog will be fully developed
247 // by then.
248 else if (descriptor->GetPluginType() == PluginTypeStub)
249 {
250 wxFileName fname{ descriptor->GetPath() };
251 variant = fname.GetName().Trim(false).Trim(true);
252 }
253 } break;
254 case ColumnPath:
255 variant = descriptor->GetPath();
256 break;
257 case ColumnType:
258 variant = descriptor->GetEffectFamily();
259 break;
260 case ColumnState:
261 variant = state;
262 break;
263 default:
264 break;
265 }
266}
267
268bool PluginDataModel::SetValue(const wxVariant& variant, const wxDataViewItem& item, unsigned col)
269{
270 if(col == ColumnState)
271 {
272 const auto index = GetRowIndex(item);
273 if(index < mPluginStateModel.size())
274 {
275 mPluginStateModel[index].second = variant.GetBool();
276 return true;
277 }
278 }
279 return false;
280}
281
282wxDataViewItem PluginDataModel::GetParent(const wxDataViewItem& item) const
283{
284 return {};
285}
286
287bool PluginDataModel::IsContainer(const wxDataViewItem& item) const
288{
289 return item.GetID() == RowIdRoot;
290}
291
292unsigned PluginDataModel::GetChildren(const wxDataViewItem& item, wxDataViewItemArray& children) const
293{
294 children.clear();
295 if(item.GetID() != RowIdRoot)
296 return 0;
297
298 children.reserve(mIndexFilterMap.size());
299 for(const auto index : mIndexFilterMap)
300 children.push_back(wxDataViewItem(index));
301
302 return children.size();
303}
304
306{
307 if(!item.IsOk())
308 return nullptr;
309 const auto index = GetRowIndex(item);
310 if(index >= mPluginStateModel.size())
311 return nullptr;
312
313 return mPluginStateModel[index].first;
314}
315
317{
318 auto textFilters = wxSplit(mFilterExpr, ' ');
319 std::for_each(
320 textFilters.begin(),
321 textFilters.end(),
322 [](wxString& str) { str.MakeLower(); }
323 );
324 mIndexFilterMap.clear();
325
326 auto filterFn = [=](PluginDescriptor* desc, bool state)
327 {
328 if((!mFilterType.empty() && desc->GetProviderID() != mFilterType) ||
329 (mFilterState != -1 && state != static_cast<bool>(mFilterState)) ||
330 (mFilterCategory != -1 && mFilterCategory != desc->GetEffectType()))
331 {
332 return false;
333 }
334
335 for(auto& filter : textFilters)
336 {
337 if((desc->GetPluginType() != PluginTypeEffect ||
338 desc->GetSymbol().Translation().Lower().Find(filter) == wxNOT_FOUND) &&
339 (desc->GetPluginType() != PluginTypeStub ||
340 wxFileName(desc->GetPath()).GetName().Lower().Find(filter) == wxNOT_FOUND))
341 {
342 return false;
343 }
344 }
345 return true;
346 };
347
348 for(uint32_t i = 0; i < mPluginStateModel.size(); ++i)
349 {
350 const auto [desc, state] = mPluginStateModel[i];
351 if(filterFn(desc, state))
352 mIndexFilterMap.push_back(MakeRow(i));
353 }
354 Cleared();
355}
356
358{
359 return mFilterState == -1 && mFilterType.empty() && mFilterExpr.empty();
360}
wxT("CloseDown"))
#define str(a)
@ EffectTypeHidden
XO("Cut/Copy/Paste")
void * MakeRow(uint32_t index)
uint32_t GetRowIndex(const wxDataViewItem &item)
@ PluginTypeStub
@ PluginTypeEffect
Abstract base class used in importing a file.
static ModuleManager & Get()
void SetFilterState(int state)
wxString GetColumnType(unsigned col) const override
std::vector< void * > mIndexFilterMap
int GetFilterCategory() const
wxDataViewItem GetParent(const wxDataViewItem &item) const override
wxDataViewItem GetItemForRow(uint32_t row) const
void SetFilterType(const wxString &type)
static const void * RowIdRoot
wxString mFilterExpr
bool IsEnabled(const wxDataViewItem &, unsigned) const override
wxString GetFilterExpr() const
PluginDataModel(int filterEffectCategory=-1, int filterState=-1, const wxString &filterType={}, const wxString &filterExpr={})
bool GetRowForItem(const wxDataViewItem &item, uint32_t &row) const
int GetFilterState() const
PluginDescriptor * GetPlugin(wxDataViewItem item)
bool SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned col) override
wxString GetFilterType() const
bool HasContainerColumns(const wxDataViewItem &item) const override
unsigned GetChildren(const wxDataViewItem &item, wxDataViewItemArray &children) const override
void SetFilterExpr(const wxString &expr)
void ApplyChanges(const std::function< bool(int, int, const wxString &)> &progressUpdateFn, const std::function< void(const TranslatableString &)> &errorFn)
unsigned GetColumnCount() const override
uint32_t GetRowCount() const
wxString mFilterType
bool IsFilterEmpty() const
void GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned col) const override
void SetFilterCategory(int category)
bool IsContainer(const wxDataViewItem &item) const override
std::vector< std::pair< PluginDescriptor *, bool > > mPluginStateModel
int Compare(const wxDataViewItem &item1, const wxDataViewItem &item2, unsigned column, bool ascending) const override
static PluginManager & Get()
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
const TranslatableString desc
Definition: ExportPCM.cpp:51
uint32_t value