KiCad PCB EDA Suite
Loading...
Searching...
No Matches
lib_tree_model.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 Chris Pavlina <[email protected]>
5 * Copyright (C) 2014 Henner Zeller <[email protected]>
6 * Copyright (C) 2023 CERN
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software: you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation, either version 3 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <lib_tree_model.h>
24
25#include <algorithm>
26#include <core/kicad_algo.h>
27#include <eda_pattern_match.h>
28#include <lib_tree_item.h>
29#include <pgm_base.h>
30#include <string_utils.h>
31
32
33
34void LIB_TREE_NODE::RebuildSearchTerms( const std::vector<wxString>& aShownColumns )
35{
37
38 for( const auto& [name, value] : m_Fields )
39 {
40 if( alg::contains( aShownColumns, name ) )
41 m_SearchTerms.push_back( SEARCH_TERM( value, 4 ) );
42 }
43}
44
45
46void LIB_TREE_NODE::AssignIntrinsicRanks( const std::vector<wxString>& aShownColumns, bool presorted )
47{
48 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
49 child->RebuildSearchTerms( aShownColumns );
50
51 std::vector<LIB_TREE_NODE*> sort_buf;
52
53 if( presorted )
54 {
55 int max = m_Children.size() - 1;
56
57 for( int i = 0; i <= max; ++i )
58 m_Children[i]->m_IntrinsicRank = max - i;
59 }
60 else
61 {
62 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
63 sort_buf.push_back( child.get() );
64
65 std::sort( sort_buf.begin(), sort_buf.end(),
66 []( LIB_TREE_NODE* a, LIB_TREE_NODE* b ) -> bool
67 {
68 return StrNumCmp( a->m_Name, b->m_Name, true ) > 0;
69 } );
70
71 for( int i = 0; i < (int) sort_buf.size(); ++i )
72 sort_buf[i]->m_IntrinsicRank = i;
73 }
74}
75
76
77void LIB_TREE_NODE::SortNodes( bool aUseScores )
78{
79 std::sort( m_Children.begin(), m_Children.end(),
80 [&]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
81 {
82 return Compare( *a, *b, aUseScores );
83 } );
84
85 for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
86 node->SortNodes( aUseScores );
87}
88
89
90bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2,
91 bool aUseScores )
92{
93 if( aNode1.m_Type != aNode2.m_Type )
94 return aNode1.m_Type < aNode2.m_Type;
95
96 // Recently used sorts at top
97 if( aNode1.m_IsRecentlyUsedGroup )
98 {
99 if( aNode2.m_IsRecentlyUsedGroup )
100 {
101 // Make sure "-- Recently Used" is always at the top
102 // Start by checking the name of aNode2, because we want to satisfy the irreflexive
103 // property of the strict weak ordering.
104 if( aNode2.m_IsRecentlyUsedGroup )
105 return false;
106 else if( aNode1.m_IsRecentlyUsedGroup )
107 return true;
108
109 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
110 }
111 else
112 {
113 return true;
114 }
115 }
116 else if( aNode2.m_Name.StartsWith( wxT( "-- " ) ) )
117 {
118 return false;
119 }
120
121 // Pinned nodes go next
122 if( aNode1.m_Pinned && !aNode2.m_Pinned )
123 return true;
124 else if( aNode2.m_Pinned && !aNode1.m_Pinned )
125 return false;
126
127 if( aUseScores && aNode1.m_Score != aNode2.m_Score )
128 return aNode1.m_Score > aNode2.m_Score;
129
130 if( aNode1.m_IntrinsicRank != aNode2.m_IntrinsicRank )
131 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
132
133 return reinterpret_cast<const void*>( &aNode1 ) < reinterpret_cast<const void*>( &aNode2 );
134}
135
136
138 : m_Parent( nullptr ),
139 m_Type( TYPE::INVALID ),
140 m_IntrinsicRank( 0 ),
141 m_Score( 0 ),
142 m_Pinned( false ),
143 m_PinCount( 0 ),
144 m_Unit( 0 ),
145 m_IsRoot( false ),
146 m_IsPower( false ),
147 m_IsRecentlyUsedGroup( false ),
149{}
150
151
153{
154 m_Parent = aParent;
155 m_Type = TYPE::UNIT;
156
157 m_Unit = aUnit;
158 m_LibId = aParent->m_LibId;
159 m_Name = aItem->GetUnitName( aUnit );
160
161 m_IntrinsicRank = -aUnit;
162}
163
164
165void LIB_TREE_NODE_UNIT::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
166 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
167{
168 m_Score = 1;
169
170 // aMatchers test results are inherited from parent
171 if( !aMatchers.empty() )
172 m_Score = m_Parent->m_Score;
173
174 if( aFilter && !(*aFilter)(*this) )
175 m_Score = 0;
176}
177
178
180{
181 m_Type = TYPE::ITEM;
182 m_Parent = aParent;
183
184 m_LibId.SetLibNickname( aItem->GetLibNickname() );
185 m_LibId.SetLibItemName( aItem->GetName() );
186
187 m_Name = aItem->GetName();
188 m_Desc = aItem->GetDesc();
189 m_Footprint = aItem->GetFootprint();
190 m_PinCount = aItem->GetPinCount();
191
192 aItem->GetChooserFields( m_Fields );
193
195
196 m_IsRoot = aItem->IsRoot();
197 m_IsPower = aItem->IsPowerSymbol();
198
199 if( aItem->GetSubUnitCount() > 1 )
200 {
201 for( int u = 1; u <= aItem->GetSubUnitCount(); ++u )
202 AddUnit( aItem, u );
203 }
204}
205
206
208{
209 LIB_TREE_NODE_UNIT* unit = new LIB_TREE_NODE_UNIT( this, aItem, aUnit );
210 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( unit ) );
211 return *unit;
212}
213
214
216{
217 m_LibId.SetLibNickname( aItem->GetLIB_ID().GetLibNickname() );
218 m_LibId.SetLibItemName( aItem->GetName() );
219
220 m_Name = aItem->GetName();
221 m_Desc = aItem->GetDesc();
222
223 aItem->GetChooserFields( m_Fields );
224
226
227 m_IsRoot = aItem->IsRoot();
228 m_IsPower = aItem->IsPowerSymbol();
229 m_Children.clear();
230
231 for( int u = 1; u <= aItem->GetSubUnitCount(); ++u )
232 AddUnit( aItem, u );
233}
234
235
236void LIB_TREE_NODE_ITEM::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
237 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
238{
239 m_Score = 1;
240
241 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : aMatchers )
242 {
243 int score = matcher->ScoreTerms( m_SearchTerms );
244
245 if( score == 0 )
246 {
247 m_Score = 0;
248 break;
249 }
250
251 m_Score += score;
252 }
253
254 if( aFilter && !(*aFilter)(*this) )
255 m_Score = 0;
256
257 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
258 child->UpdateScore( aMatchers, aFilter );
259}
260
261
263 wxString const& aDesc )
264{
265 m_Type = TYPE::LIBRARY;
266 m_Name = aName;
267 m_Desc = aDesc;
268 m_Parent = aParent;
269 m_LibId.SetLibNickname( aName );
270
271 m_SearchTerms.emplace_back( SEARCH_TERM( aName, 8 ) );
272}
273
274
276{
277 LIB_TREE_NODE_ITEM* item = new LIB_TREE_NODE_ITEM( this, aItem );
278 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
279 return *item;
280}
281
282
283void LIB_TREE_NODE_LIBRARY::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
284 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
285{
286 if( m_Children.empty() )
287 {
288 m_Score = 1;
289
290 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : aMatchers )
291 {
292 int score = matcher->ScoreTerms( m_SearchTerms );
293
294 if( score == 0 )
295 {
296 m_Score = 0;
297 break;
298 }
299
300 m_Score += score;
301 }
302 }
303 else
304 {
305 m_Score = 0;
306
307 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
308 {
309 child->UpdateScore( aMatchers, aFilter );
310 m_Score = std::max( m_Score, child->m_Score );
311 }
312 }
313}
314
315
317{
318 m_Type = TYPE::ROOT;
319}
320
321
322LIB_TREE_NODE_LIBRARY& LIB_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString const& aDesc )
323{
324 LIB_TREE_NODE_LIBRARY* lib = new LIB_TREE_NODE_LIBRARY( this, aName, aDesc );
325 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( lib ) );
326 return *lib;
327}
328
329
330void LIB_TREE_NODE_ROOT::RemoveGroup( bool aRecentlyUsedGroup, bool aAlreadyPlacedGroup )
331{
332 m_Children.erase( std::remove_if( m_Children.begin(), m_Children.end(),
333 [&]( std::unique_ptr<LIB_TREE_NODE>& aNode )
334 {
335 if( aRecentlyUsedGroup && aNode->m_IsRecentlyUsedGroup )
336 return true;
337
338 if( aAlreadyPlacedGroup && aNode->m_IsAlreadyPlacedGroup )
339 return true;
340
341 return false;
342 } ),
343 m_Children.end() );
344}
345
346
348{
349 m_Children.clear();
350}
351
352
353void LIB_TREE_NODE_ROOT::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
354 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
355{
356 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
357 child->UpdateScore( aMatchers, aFilter );
358}
359
const char * name
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
virtual wxString GetLibNickname() const =0
virtual int GetSubUnitCount() const
For items with units, return the number of units.
virtual wxString GetUnitName(int aUnit) const
For items with units, return an identifier for unit x.
virtual wxString GetFootprint()
For items with footprint fields.
virtual bool IsPowerSymbol() const
For symbols that could be a power symbol.
virtual LIB_ID GetLIB_ID() const =0
virtual wxString GetDesc()=0
virtual bool IsRoot() const
For items having aliases, IsRoot() indicates the principal item.
virtual wxString GetName() const =0
virtual std::vector< SEARCH_TERM > & GetSearchTerms()=0
virtual int GetPinCount()
The pin count for symbols or the unique pad count for footprints.
virtual void GetChooserFields(std::map< wxString, wxString > &aColumnMap)
Retrieves a key/value map of the fields on this item that should be exposed to the library browser/ch...
Node type: LIB_ID.
void UpdateScore(const std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > &aMatchers, std::function< bool(LIB_TREE_NODE &aNode)> *aFilter) override
Perform the actual search.
LIB_TREE_NODE_ITEM(LIB_TREE_NODE_ITEM const &_)=delete
The addresses of CMP_TREE_NODEs are used as unique IDs for the wxDataViewModel, so don't let them be ...
LIB_TREE_NODE_UNIT & AddUnit(LIB_TREE_ITEM *aItem, int aUnit)
Add a new unit to the component and return it.
void Update(LIB_TREE_ITEM *aItem)
Update the node using data from a LIB_ALIAS object.
Node type: library.
LIB_TREE_NODE_LIBRARY(LIB_TREE_NODE_LIBRARY const &_)=delete
The addresses of CMP_TREE_NODEs are used as unique IDs for the wxDataViewModel, so don't let them be ...
void UpdateScore(const std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > &aMatchers, std::function< bool(LIB_TREE_NODE &aNode)> *aFilter) override
Update the score for this part.
LIB_TREE_NODE_ITEM & AddItem(LIB_TREE_ITEM *aItem)
Construct a new alias node, add it to this library, and return it.
void RemoveGroup(bool aRecentlyUsedGroup, bool aAlreadyPlacedGroup)
Remove a library node from the root.
LIB_TREE_NODE_LIBRARY & AddLib(wxString const &aName, wxString const &aDesc)
Construct an empty library node, add it to the root, and return it.
LIB_TREE_NODE_ROOT()
Construct the root node.
void UpdateScore(const std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > &aMatchers, std::function< bool(LIB_TREE_NODE &aNode)> *aFilter) override
Update the score for this part.
void Clear()
Clear the tree.
Node type: unit of component.
LIB_TREE_NODE_UNIT(LIB_TREE_NODE_UNIT const &_)=delete
The addresses of CMP_TREE_NODEs are used as unique IDs for the wxDataViewModel, so don't let them be ...
void UpdateScore(const std::vector< std::unique_ptr< EDA_COMBINED_MATCHER > > &aMatchers, std::function< bool(LIB_TREE_NODE &aNode)> *aFilter) override
Update the score for this part.
void SortNodes(bool aUseScores)
Sort child nodes quickly and recursively (IntrinsicRanks must have been set).
void RebuildSearchTerms(const std::vector< wxString > &aShownColumns)
Rebuild search terms from source search terms and shown fields.
static bool Compare(LIB_TREE_NODE const &aNode1, LIB_TREE_NODE const &aNode2, bool aUseScores)
Compare two nodes.
bool m_IsAlreadyPlacedGroup
std::span< SEARCH_TERM > m_sourceSearchTerms
std::vector< SEARCH_TERM > m_SearchTerms
std::map< wxString, wxString > m_Fields
List of weighted search terms.
PTR_VECTOR m_Children
wxString m_Footprint
LIB_TREE_NODE * m_Parent
int m_IntrinsicRank
The rank of the item before any search terms are applied.
void AssignIntrinsicRanks(const std::vector< wxString > &aShownColumns, bool presorted=false)
Store intrinsic ranks on all children of this node.
Abstract pattern-matching tool and implementations.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
see class PGM_BASE
A structure for storing weighted search terms.