13#include <unordered_set>
29 , ordering{ ordering == Strong ? Weak : ordering }
56 auto end = items.end();
59 : std::find_if( items.begin(),
end,
60 [&](
const Item& item ){
61 return name == item.visitNow->name; } );
64 auto InsertNewItemUsingPreferences(
67 auto InsertNewItemUsingHint(
75 void SubordinateSingleItem(Item &found,
BaseItem *pItem);
77 void SubordinateMultipleItems(Item &found,
GroupItemBase &items);
79 auto MergeWithExistingItem(
82 using NewItem = std::pair< BaseItem*, OrderingHint >;
85 auto MergeLikeNamedItems(
87 NewItems::const_iterator left, NewItems::const_iterator right,
88 int iPass,
size_t endItemsCount,
bool force )
91 auto MergeItemsAscendingNamesPass(
93 NewItems &newItems,
int iPass,
size_t endItemsCount,
bool force )
96 auto MergeItemsDescendingNamesPass(
98 NewItems &newItems,
int iPass,
size_t endItemsCount,
bool force )
110 return !delegate || delegate->
orderingHint.type == OrderingHint::Unspecified
128 for (
auto &item : items )
139 if (
const auto pIndirect =
140 dynamic_cast<IndirectItemBase*
>(pItem)) {
141 auto delegate = pIndirect->ptr.get();
145 ChooseHint(delegate, pIndirect->orderingHint));
148 if (
const auto pComputed =
149 dynamic_cast<ComputedItemBase*
>(pItem)) {
156 ChooseHint( result.get(), pComputed->orderingHint ) );
161 if (pGroup->GetOrdering() == GroupItemBase::Anonymous)
169 collection.
items.push_back( {pItem,
nullptr, hint} );
174 collection.
items.push_back( {pItem,
nullptr, hint} );
178using Path = std::vector< Identifier >;
185 auto badPath =
key +
'/' +
name.GET();
186 if (
sBadPaths.insert( badPath ).second ) {
189 wxLogDebug( msg.Translation() );
200XO(
"Plug-in group at %s was merged with a previously defined group"),
207XO(
"Plug-in item at %s conflicts with a previously defined item and was discarded"),
214XO(
"Plug-in items at %s specify conflicting placements"),
227 wxArrayString strings;
228 for (
const auto &
id : path)
229 strings.push_back(
id.GET() );
230 key =
'/' + ::wxJoin( strings,
'/',
'\0' );
234 bool gotOrdering =
false;
238 auto Get() -> wxArrayString & {
239 if ( !gotOrdering ) {
241 ordering = ::wxSplit( strValue,
',' );
253auto CollectedItems::InsertNewItemUsingPreferences(
266 if ( !pItem->name.empty() ) {
268 auto &ordering = itemOrdering.Get();
269 auto begin2 = ordering.begin(), end2 = ordering.end(),
270 found2 = std::find( begin2, end2, pItem->name );
271 if ( found2 != end2 ) {
272 auto insertPoint = items.end();
275 while ( ++found2 != end2 ) {
276 auto known =
Find( *found2 );
277 if ( known != insertPoint ) {
282 items.insert( insertPoint, {pItem,
nullptr,
294auto CollectedItems::InsertNewItemUsingHint(
298 auto begin = items.begin(),
end = items.end(),
299 insertPoint =
end - endItemsCount;
303 if ( pItem->name.empty() ) {
308 switch ( hint.type ) {
309 case OrderingHint::Before:
310 case OrderingHint::After: {
312 auto found =
Find( hint.name );
313 if ( found ==
end ) {
321 if ( hint.type == OrderingHint::After )
329 case OrderingHint::End:
332 case OrderingHint::Unspecified:
341 items.insert( insertPoint, {pItem,
nullptr,
350 auto subGroup = found.mergeLater;
352 auto newGroup = std::make_shared<PlaceHolder>(
name, ordering);
353 computedItems.push_back(newGroup);
354 subGroup = found.mergeLater = newGroup.get();
359void CollectedItems::SubordinateSingleItem(
Item &found,
BaseItem *pItem)
361 MergeLater(found, pItem->
name, GroupItemBase::Weak)->push_back(
362 std::make_unique<IndirectItemBase>(
364 std::shared_ptr<BaseItem>(pItem, [](
void*){})));
369 auto subGroup = MergeLater(found, items.name, items.
GetOrdering());
370 for (
const auto &pItem : items)
371 subGroup->push_back(std::make_unique<IndirectItemBase>(
373 std::shared_ptr<BaseItem>(pItem.get(), [](
void*){})));
376auto CollectedItems::MergeWithExistingItem(
380 const auto &
name = pItem->name;
382 if (found != items.end()) {
386 auto pCollectionGroup =
dynamic_cast< GroupItemBase *
>( found->visitNow );
387 auto pRegistryGroup =
dynamic_cast< GroupItemBase *
>( pItem );
388 if (pCollectionGroup) {
389 if (pRegistryGroup) {
396 bool pCollectionGrouping =
397 (pCollectionGroup->GetOrdering() != GroupItemBase::Strong);
398 auto pRegistryGrouping =
399 (pRegistryGroup->GetOrdering() != GroupItemBase::Strong);
400 if ( !(pCollectionGrouping || pRegistryGrouping) )
403 if ( pCollectionGrouping && !pRegistryGrouping ) {
405 found->visitNow = pRegistryGroup;
406 SubordinateMultipleItems(*found, *pCollectionGroup);
409 SubordinateMultipleItems(*found, *pRegistryGroup);
416 SubordinateSingleItem(*found, pItem);
420 if (pRegistryGroup) {
425 auto demoted = found->visitNow;
426 found->visitNow = pRegistryGroup;
427 SubordinateSingleItem(*found, demoted);
443auto CollectedItems::MergeLikeNamedItems(
445 NewItems::const_iterator left, NewItems::const_iterator right,
446 const int iPass,
size_t endItemsCount,
bool force )
455 auto pItem = item.first;
456 const auto &hint = item.second;
457 bool success =
false;
460 success = InsertNewItemUsingPreferences( itemOrdering, pItem );
461 else if ( iPass == hint.type ) {
466 InsertNewItemUsingHint( pItem, hint, endItemsCount, force );
467 wxASSERT( !force || success );
473 if ( iter != right && iPass != 0 &&
474 iter->second.type != OrderingHint::Unspecified &&
475 !( iter->second == hint ) ) {
479 while ( iter != right )
482 MergeWithExistingItem( visitor, itemOrdering, iter++ -> first );
491 return a.first->name > b.first->name;
497 return a.second < b.second;
508auto CollectedItems::MergeItemsAscendingNamesPass(
510 const int iPass,
size_t endItemsCount,
bool force ) ->
void
513 auto rright = newItems.rbegin();
514 auto rend = newItems.rend();
515 while ( rright != rend ) {
517 using namespace std::placeholders;
518 auto rleft = std::find_if(
519 rright + 1, rend, std::bind(
MajorComp, _1, *rright ) );
521 bool success = MergeLikeNamedItems(
522 visitor, itemOrdering, rleft.base(), rright.base(), iPass,
523 endItemsCount, force );
526 auto diff = rend - rleft;
527 newItems.erase( rleft.base(), rright.base() );
528 rend = newItems.rend();
535auto CollectedItems::MergeItemsDescendingNamesPass(
537 const int iPass,
size_t endItemsCount,
bool force ) ->
void
540 auto left = newItems.begin();
541 while ( left != newItems.end() ) {
543 using namespace std::placeholders;
544 auto right = std::find_if(
545 left + 1, newItems.end(), std::bind(
MajorComp, *left, _1 ) );
547 bool success = MergeLikeNamedItems(
548 visitor, itemOrdering, left, right, iPass,
549 endItemsCount, force );
552 left = newItems.erase( left, right );
558auto CollectedItems::MergeItems(
572 for (
const auto &item : newCollection.items)
573 if (!MergeWithExistingItem(visitor, itemOrdering, item.visitNow))
574 newItems.push_back({ item.visitNow, item.hint });
581 std::sort( newItems.begin(), newItems.end(),
Comp );
587 size_t endItemsCount = 0;
588 auto prevSize = newItems.size();
589 while( !newItems.empty() )
599 MergeItemsDescendingNamesPass(
600 visitor, itemOrdering, newItems, iPass, endItemsCount, force );
602 MergeItemsAscendingNamesPass(
603 visitor, itemOrdering, newItems, iPass, endItemsCount, force );
605 auto newSize = newItems.size();
611 else if ( iPass == OrderingHint::Unspecified ) {
613 iPass = 0, oldSize = newSize;
615 bool progress = ( oldSize > newSize );
624 else if (iPass == OrderingHint::End && endItemsCount == 0)
626 assert(newSize >= prevSize || newSize == 0);
628 endItemsCount = newSize - prevSize;
654 path.push_back(group.name.GET());
660 newCollection.MergeItems(visitor, itemOrdering, *pToMerge, hint);
664 if ( itemOrdering.gotOrdering ) {
666 for (
const auto &item : newCollection.items ) {
667 const auto &
name = item.visitNow->name;
669 newValue += newValue.
empty()
673 if (newValue != itemOrdering.strValue) {
681 for (
const auto &item : newCollection.items )
683 item.visitNow, item.mergeLater, item.hint,
697 if (
const auto pSingle =
699 wxASSERT( !pToMerge );
700 visitor.
Visit( *pSingle, path );
703 if (
const auto pGroup =
707 VisitItems(visitor, collection, path, *pGroup, pToMerge, hint, doFlush);
720IndirectItemBase::~IndirectItemBase() {}
722ComputedItemBase::~ComputedItemBase() {}
741 std::vector< BaseItemSharedPtr > computedItems;
742 bool doFlush =
false;
743 CollectedItems collection{ {}, computedItems };
746 visitor, collection, emptyPath, pTopItem,
747 pRegistry, pRegistry->orderingHint, doFlush );
755 : mPairs{
std::move( pairs ) }
763 bool doFlush =
false;
764 for (
const auto &pair :
mPairs) {
765 const auto key = wxString{
'/'} +
mRoot + pair.first;
781 std::vector<BaseItemPtr> *pItems{};
785 return component < pItem->name; }
788 return pItem->name < component; }
790 auto find = [&pItems](
const Identifier &component ){
return std::equal_range(
791 pItems->begin(), pItems->end(), component, Comparator() ); };
793 auto pNode = ®istry;
794 pItems = &pNode->
items;
796 const auto pathComponents = ::wxSplit( placement.
path,
'/' );
797 auto pComponent = pathComponents.begin(),
end = pathComponents.end();
801 auto debugPath = wxString{
'/'} + registry.name.GET();
802 while ( pComponent !=
end ) {
803 const auto &pathComponent = *pComponent;
807 const auto range = find( pathComponent );
808 const auto iter2 = std::find_if( range.first, range.second,
810 return dynamic_cast< GroupItemBase* >( pItem.get() ); } );
812 if ( iter2 != range.second ) {
815 pItems = &pNode->
items;
816 debugPath +=
'/' + pathComponent;
828 while ( pComponent !=
end ) {
831 pNode = newNode.get();
832 pItems->insert( find( pNode->name ).second, std::move( newNode ) );
833 pItems = &pNode->items;
838 pItem->orderingHint = placement.
hint;
841 pItems->insert( find( pItem->name ).second, std::move( pItem ) );
Toolkit-neutral facade for basic user interface services.
static const AudacityProject::AttachedObjects::RegisteredFactory key
const TranslatableString name
audacity::BasicSettings * gPrefs
An explicitly nonlocalized string, not meant for the user to see.
virtual void BeginGroup(GroupItemBase &item, const Path &path)
virtual void * GetComputedItemContext()
Get context given to Computed items during visitation.
virtual void EndGroup(GroupItemBase &item, const Path &path)
std::vector< Identifier > Path
virtual void Visit(SingleItem &item, const Path &path)
Holds a msgid for the translation catalog; may also bind format arguments.
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
PROJECT_FILE_IO_API wxString Find(const FilePath &path)
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
bool Begin(const FilePath &dataDir)
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
void RegisterItem(GroupItemBase ®istry, const Placement &placement, BaseItemPtr pItem)
std::unique_ptr< BaseItem > BaseItemPtr
void Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItemBase *pRegistry)
void CollectItem(Registry::Visitor &visitor, CollectedItems &collection, BaseItem *Item, const OrderingHint &hint)
bool MinorComp(const CollectedItems::NewItem &a, const CollectedItems::NewItem &b)
void ReportConflictingPlacements(const wxString &key, const Identifier &name)
std::vector< Identifier > Path
void VisitItems(Registry::Visitor &visitor, CollectedItems &collection, Path &path, const GroupItemBase &group, const GroupItemBase *pToMerge, const OrderingHint &hint, bool &doFlush)
void ReportItemItemCollision(const wxString &key, const Identifier &name)
std::unordered_set< wxString > sBadPaths
bool Comp(const CollectedItems::NewItem &a, const CollectedItems::NewItem &b)
const OrderingHint & ChooseHint(BaseItem *delegate, const OrderingHint &hint)
void VisitItem(Registry::Visitor &visitor, CollectedItems &collection, Path &path, BaseItem *pItem, const GroupItemBase *pToMerge, const OrderingHint &hint, bool &doFlush)
void BadPath(const TranslatableString &format, const wxString &key, const Identifier &name)
bool MajorComp(const CollectedItems::NewItem &a, const CollectedItems::NewItem &b)
void CollectItems(Registry::Visitor &visitor, CollectedItems &collection, const GroupItemBase &items, const OrderingHint &hint)
void ReportGroupGroupCollision(const wxString &key, const Identifier &name)
OrderingHint orderingHint
Common abstract base class for items that group other items.
~GroupItemBase() override=0
Ordering
Choose treatment of the children of the group when merging trees.
virtual Ordering GetOrdering() const
Default implementation returns Strong.
Extends GroupItemBase with a variadic constructor.
void operator()() override
std::vector< Pair > Pairs
OrderingPreferenceInitializer(Literal root, Pairs pairs)
Common abstract base class for items that are not groups.
GroupItemBase * mergeLater
std::vector< BaseItemSharedPtr > & computedItems
decltype(items)::iterator Iterator
std::vector< NewItem > NewItems
auto Find(const Identifier &name) -> Iterator
std::pair< BaseItem *, OrderingHint > NewItem
std::vector< Item > items
ItemOrdering(const Path &path)
auto Get() -> wxArrayString &
PlaceHolder(const Identifier &identifier, Ordering ordering)
Ordering GetOrdering() const override
Default implementation returns Strong.