13#include <unordered_set>
41 auto end = items.end();
44 : std::find_if( items.begin(),
end,
45 [&](
const Item& item ){
46 return name == item.visitNow->name; } );
49 auto InsertNewItemUsingPreferences(
52 auto InsertNewItemUsingHint(
59 auto SubordinateSingleItem( Item &found,
BaseItem *pItem ) -> void;
61 auto SubordinateMultipleItems( Item &found,
GroupItem *pItems ) -> void;
63 auto MergeWithExistingItem(
66 using NewItem = std::pair< BaseItem*, OrderingHint >;
69 auto MergeLikeNamedItems(
71 NewItems::const_iterator left, NewItems::const_iterator right,
72 int iPass,
size_t endItemsCount,
bool force )
75 auto MergeItemsAscendingNamesPass(
77 NewItems &newItems,
int iPass,
size_t endItemsCount,
bool force )
80 auto MergeItemsDescendingNamesPass(
82 NewItems &newItems,
int iPass,
size_t endItemsCount,
bool force )
94 return !delegate || delegate->
orderingHint.type == OrderingHint::Unspecified
112 for (
auto &item : items )
123 if (
const auto pShared =
125 auto delegate = pShared->ptr.get();
129 ChooseHint( delegate, pShared->orderingHint ) );
132 if (
const auto pComputed =
134 auto result = pComputed->factory( visitor );
140 ChooseHint( result.get(), pComputed->orderingHint ) );
144 if (
auto pGroup =
dynamic_cast<GroupItem*
>(pItem)) {
145 if (pGroup->Transparent() && pItem->
name.
empty())
154 collection.
items.push_back( {pItem,
nullptr, hint} );
159 collection.
items.push_back( {pItem,
nullptr, hint} );
163using Path = std::vector< Identifier >;
170 auto badPath =
key +
'/' +
name.GET();
171 if (
sBadPaths.insert( badPath ).second ) {
174 wxLogDebug( msg.Translation() );
185XO(
"Plug-in group at %s was merged with a previously defined group"),
192XO(
"Plug-in item at %s conflicts with a previously defined item and was discarded"),
199XO(
"Plug-in items at %s specify conflicting placements"),
212 wxArrayString strings;
213 for (
const auto &
id : path)
214 strings.push_back(
id.GET() );
215 key =
'/' + ::wxJoin( strings,
'/',
'\0' );
219 bool gotOrdering =
false;
223 auto Get() -> wxArrayString & {
224 if ( !gotOrdering ) {
226 ordering = ::wxSplit( strValue,
',' );
238auto CollectedItems::InsertNewItemUsingPreferences(
251 if ( !pItem->name.empty() ) {
253 auto &ordering = itemOrdering.Get();
254 auto begin2 = ordering.begin(), end2 = ordering.end(),
255 found2 = std::find( begin2, end2, pItem->name );
256 if ( found2 != end2 ) {
257 auto insertPoint = items.end();
260 while ( ++found2 != end2 ) {
261 auto known =
Find( *found2 );
262 if ( known != insertPoint ) {
267 items.insert( insertPoint, {pItem,
nullptr,
279auto CollectedItems::InsertNewItemUsingHint(
283 auto begin = items.begin(),
end = items.end(),
284 insertPoint =
end - endItemsCount;
288 if ( pItem->name.empty() ) {
293 switch ( hint.type ) {
294 case OrderingHint::Before:
295 case OrderingHint::After: {
297 auto found =
Find( hint.name );
298 if ( found ==
end ) {
306 if ( hint.type == OrderingHint::After )
314 case OrderingHint::End:
317 case OrderingHint::Unspecified:
326 items.insert( insertPoint, {pItem,
nullptr,
335 auto subGroup = found.mergeLater;
337 auto newGroup = std::make_shared<TransparentGroupItem<>>(
name );
338 computedItems.push_back( newGroup );
339 subGroup = found.mergeLater = newGroup.get();
344auto CollectedItems::SubordinateSingleItem(
Item &found,
BaseItem *pItem )
347 MergeLater( found, pItem->name )->
items.push_back(
348 std::make_unique<SharedItem>(
350 std::shared_ptr<BaseItem>( pItem, [](
void*){} ) ) );
353auto CollectedItems::SubordinateMultipleItems(
Item &found,
GroupItem *pItems )
356 auto subGroup = MergeLater( found, pItems->name );
357 for (
const auto &pItem : pItems->items )
358 subGroup->items.push_back( std::make_unique<SharedItem>(
360 std::shared_ptr<BaseItem>( pItem.get(), [](
void*){} ) ) );
363auto CollectedItems::MergeWithExistingItem(
367 const auto &
name = pItem->name;
369 if (found != items.end()) {
373 auto pCollectionGroup =
dynamic_cast< GroupItem *
>( found->visitNow );
374 auto pRegistryGroup =
dynamic_cast< GroupItem *
>( pItem );
375 if (pCollectionGroup) {
376 if (pRegistryGroup) {
383 bool pCollectionGrouping = pCollectionGroup->
Transparent();
384 auto pRegistryGrouping = pRegistryGroup->Transparent();
385 if ( !(pCollectionGrouping || pRegistryGrouping) )
388 if ( pCollectionGrouping && !pRegistryGrouping ) {
390 found->visitNow = pRegistryGroup;
391 SubordinateMultipleItems( *found, pCollectionGroup );
394 SubordinateMultipleItems( *found, pRegistryGroup );
401 SubordinateSingleItem( *found, pItem );
405 if (pRegistryGroup) {
410 auto demoted = found->visitNow;
411 found->visitNow = pRegistryGroup;
412 SubordinateSingleItem( *found, demoted );
428auto CollectedItems::MergeLikeNamedItems(
430 NewItems::const_iterator left, NewItems::const_iterator right,
431 const int iPass,
size_t endItemsCount,
bool force )
440 auto pItem = item.first;
441 const auto &hint = item.second;
442 bool success =
false;
445 success = InsertNewItemUsingPreferences( itemOrdering, pItem );
446 else if ( iPass == hint.type ) {
451 InsertNewItemUsingHint( pItem, hint, endItemsCount, force );
452 wxASSERT( !force || success );
458 if ( iter != right && iPass != 0 &&
459 iter->second.type != OrderingHint::Unspecified &&
460 !( iter->second == hint ) ) {
464 while ( iter != right )
467 MergeWithExistingItem( visitor, itemOrdering, iter++ -> first );
476 return a.first->name > b.first->name;
482 return a.second < b.second;
493auto CollectedItems::MergeItemsAscendingNamesPass(
495 const int iPass,
size_t endItemsCount,
bool force ) ->
void
498 auto rright = newItems.rbegin();
499 auto rend = newItems.rend();
500 while ( rright != rend ) {
502 using namespace std::placeholders;
503 auto rleft = std::find_if(
504 rright + 1, rend, std::bind(
MajorComp, _1, *rright ) );
506 bool success = MergeLikeNamedItems(
507 visitor, itemOrdering, rleft.base(), rright.base(), iPass,
508 endItemsCount, force );
511 auto diff = rend - rleft;
512 newItems.erase( rleft.base(), rright.base() );
513 rend = newItems.rend();
520auto CollectedItems::MergeItemsDescendingNamesPass(
522 const int iPass,
size_t endItemsCount,
bool force ) ->
void
525 auto left = newItems.begin();
526 while ( left != newItems.end() ) {
528 using namespace std::placeholders;
529 auto right = std::find_if(
530 left + 1, newItems.end(), std::bind(
MajorComp, *left, _1 ) );
532 bool success = MergeLikeNamedItems(
533 visitor, itemOrdering, left, right, iPass,
534 endItemsCount, force );
537 left = newItems.erase( left, right );
543auto CollectedItems::MergeItems(
555 for (
const auto &item : newCollection.items )
556 if ( !MergeWithExistingItem( visitor, itemOrdering, item.visitNow ) )
557 newItems.push_back( { item.visitNow, item.hint } );
563 std::sort( newItems.begin(), newItems.end(),
Comp );
569 size_t endItemsCount = 0;
570 auto prevSize = newItems.size();
571 while( !newItems.empty() )
581 MergeItemsDescendingNamesPass(
582 visitor, itemOrdering, newItems, iPass, endItemsCount, force );
584 MergeItemsAscendingNamesPass(
585 visitor, itemOrdering, newItems, iPass, endItemsCount, force );
587 auto newSize = newItems.size();
593 else if ( iPass == OrderingHint::Unspecified ) {
595 iPass = 0, oldSize = newSize;
597 bool progress = ( oldSize > newSize );
606 else if ( iPass == OrderingHint::End && endItemsCount == 0 )
608 endItemsCount = newSize - prevSize;
633 path.push_back( pGroup->
name.
GET() );
639 newCollection.MergeItems( visitor, itemOrdering, pToMerge->
items, hint );
643 if ( itemOrdering.gotOrdering ) {
645 for (
const auto &item : newCollection.items ) {
646 const auto &
name = item.visitNow->name;
648 newValue += newValue.
empty()
652 if (newValue != itemOrdering.strValue) {
653 gPrefs->Write( itemOrdering.key, newValue );
660 for (
const auto &item : newCollection.items )
662 item.visitNow, item.mergeLater, item.hint,
676 if (
const auto pSingle =
678 wxASSERT( !pToMerge );
679 visitor.
Visit( *pSingle, path );
682 if (
const auto pGroup =
687 visitor, collection, path, pGroup, pToMerge, hint, doFlush );
715 std::vector< BaseItemSharedPtr > computedItems;
716 bool doFlush =
false;
717 CollectedItems collection{ {}, computedItems };
720 visitor, collection, emptyPath, pTopItem,
729 : mPairs{
std::move( pairs ) }
737 bool doFlush =
false;
738 for (
const auto &pair :
mPairs) {
739 const auto key = wxString{
'/'} +
mRoot + pair.first;
759 return component < pItem->name; }
762 return pItem->name < component; }
764 auto find = [&pItems](
const Identifier &component ){
return std::equal_range(
765 pItems->begin(), pItems->end(), component, Comparator() ); };
767 auto pNode = ®istry;
768 pItems = &pNode->
items;
770 const auto pathComponents = ::wxSplit( placement.
path,
'/' );
771 auto pComponent = pathComponents.begin(),
end = pathComponents.end();
775 auto debugPath = wxString{
'/'} + registry.
name.
GET();
776 while ( pComponent !=
end ) {
777 const auto &pathComponent = *pComponent;
781 const auto range = find( pathComponent );
782 const auto iter2 = std::find_if( range.first, range.second,
784 return dynamic_cast< GroupItem* >( pItem.get() ); } );
786 if ( iter2 != range.second ) {
788 pNode =
static_cast< GroupItem*
>( iter2->get() );
789 pItems = &pNode->
items;
790 debugPath +=
'/' + pathComponent;
802 while ( pComponent !=
end ) {
803 auto newNode = std::make_unique<TransparentGroupItem<>>( *pComponent );
804 pNode = newNode.get();
805 pItems->insert( find( pNode->name ).second, std::move( newNode ) );
806 pItems = &pNode->items;
811 pItem->orderingHint = placement.
hint;
814 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
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
An explicitly nonlocalized string, not meant for the user to see.
const wxString & GET() const
Explicit conversion to wxString, meant to be ugly-looking and demanding of a comment why it's correct...
virtual void BeginGroup(GroupItem &item, const Path &path)
std::vector< Identifier > Path
virtual void EndGroup(GroupItem &item, const Path &path)
virtual void Visit(SingleItem &item, const Path &path)
Holds a msgid for the translation catalog; may also bind format arguments.
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 Visit(Visitor &visitor, BaseItem *pTopItem, const GroupItem *pRegistry)
std::unique_ptr< BaseItem > BaseItemPtr
std::vector< BaseItemPtr > BaseItemPtrs
void RegisterItem(GroupItem ®istry, const Placement &placement, BaseItemPtr pItem)
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 VisitItem(Registry::Visitor &visitor, CollectedItems &collection, Path &path, BaseItem *pItem, const GroupItem *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)
void CollectItems(Registry::Visitor &visitor, CollectedItems &collection, const BaseItemPtrs &items, const OrderingHint &hint)
const OrderingHint & ChooseHint(BaseItem *delegate, const OrderingHint &hint)
void VisitItems(Registry::Visitor &visitor, CollectedItems &collection, Path &path, GroupItem *pGroup, const GroupItem *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 ReportGroupGroupCollision(const wxString &key, const Identifier &name)
OrderingHint orderingHint
virtual bool Transparent() const =0
void operator()() override
std::vector< Pair > Pairs
OrderingPreferenceInitializer(Literal root, Pairs pairs)
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 &