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 <eda_pattern_match.h>
27#include <lib_tree_item.h>
28#include <pgm_base.h>
29#include <string_utils.h>
30
31
32
34{
35 std::vector<LIB_TREE_NODE*> sort_buf;
36
37 if( presorted )
38 {
39 int max = m_Children.size() - 1;
40
41 for( int i = 0; i <= max; ++i )
42 m_Children[i]->m_IntrinsicRank = max - i;
43 }
44 else
45 {
46 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
47 sort_buf.push_back( child.get() );
48
49 std::sort( sort_buf.begin(), sort_buf.end(),
50 []( LIB_TREE_NODE* a, LIB_TREE_NODE* b ) -> bool
51 {
52 return StrNumCmp( a->m_Name, b->m_Name, true ) > 0;
53 } );
54
55 for( int i = 0; i < (int) sort_buf.size(); ++i )
56 sort_buf[i]->m_IntrinsicRank = i;
57 }
58}
59
60
61void LIB_TREE_NODE::SortNodes( bool aUseScores )
62{
63 std::sort( m_Children.begin(), m_Children.end(),
64 [&]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
65 {
66 return Compare( *a, *b, aUseScores );
67 } );
68
69 for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
70 node->SortNodes( aUseScores );
71}
72
73
74bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2,
75 bool aUseScores )
76{
77 if( aNode1.m_Type != aNode2.m_Type )
78 return aNode1.m_Type < aNode2.m_Type;
79
80 // Recently used sorts at top
81 if( aNode1.m_IsRecentlyUsedGroup )
82 {
83 if( aNode2.m_IsRecentlyUsedGroup )
84 {
85 // Make sure "-- Recently Used" is always at the top
86 // Start by checking the name of aNode2, because we want to satisfy the irreflexive
87 // property of the strict weak ordering.
88 if( aNode2.m_IsRecentlyUsedGroup )
89 return false;
90 else if( aNode1.m_IsRecentlyUsedGroup )
91 return true;
92
93 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
94 }
95 else
96 {
97 return true;
98 }
99 }
100 else if( aNode2.m_Name.StartsWith( wxT( "-- " ) ) )
101 {
102 return false;
103 }
104
105 // Pinned nodes go next
106 if( aNode1.m_Pinned && !aNode2.m_Pinned )
107 return true;
108 else if( aNode2.m_Pinned && !aNode1.m_Pinned )
109 return false;
110
111 if( aUseScores && aNode1.m_Score != aNode2.m_Score )
112 return aNode1.m_Score > aNode2.m_Score;
113
114 if( aNode1.m_IntrinsicRank != aNode2.m_IntrinsicRank )
115 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
116
117 return reinterpret_cast<const void*>( &aNode1 ) < reinterpret_cast<const void*>( &aNode2 );
118}
119
120
122 : m_Parent( nullptr ),
123 m_Type( TYPE::INVALID ),
124 m_IntrinsicRank( 0 ),
125 m_Score( 0 ),
126 m_Pinned( false ),
127 m_PinCount( 0 ),
128 m_Unit( 0 ),
129 m_IsRoot( false ),
130 m_IsRecentlyUsedGroup( false ),
131 m_IsAlreadyPlacedGroup( false )
132{}
133
134
136{
137 static void* locale = nullptr;
138 static wxString namePrefix;
139
140 // Fetching translations can take a surprising amount of time when loading libraries,
141 // so only do it when necessary.
142 if( Pgm().GetLocale() != locale )
143 {
144 namePrefix = _( "Unit" );
145 locale = Pgm().GetLocale();
146 }
147
148 m_Parent = aParent;
149 m_Type = TYPE::UNIT;
150
151 m_Unit = aUnit;
152 m_LibId = aParent->m_LibId;
153
154 m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
155
156 if( aItem->HasUnitDisplayName( aUnit ) )
157 m_Desc = aItem->GetUnitDisplayName( aUnit );
158 else
159 m_Desc = wxEmptyString;
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() )
173
174 if( aFilter && !(*aFilter)(*this) )
175 m_Score = 0;
176}
177
178
180{
181 m_Type = TYPE::ITEM;
182 m_Parent = aParent;
183
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
194 m_SearchTerms = aItem->GetSearchTerms();
195
196 m_IsRoot = aItem->IsRoot();
197
198 if( aItem->GetSubUnitCount() > 1 )
199 {
200 for( int u = 1; u <= aItem->GetSubUnitCount(); ++u )
201 AddUnit( aItem, u );
202 }
203}
204
205
207{
208 LIB_TREE_NODE_UNIT* unit = new LIB_TREE_NODE_UNIT( this, aItem, aUnit );
209 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( unit ) );
210 return *unit;
211}
212
213
215{
217 m_LibId.SetLibItemName( aItem->GetName() );
218
219 m_Name = aItem->GetName();
220 m_Desc = aItem->GetDesc();
221
222 aItem->GetChooserFields( m_Fields );
223
224 m_SearchTerms = aItem->GetSearchTerms();
225
226 m_IsRoot = aItem->IsRoot();
227 m_Children.clear();
228
229 for( int u = 1; u <= aItem->GetSubUnitCount(); ++u )
230 AddUnit( aItem, u );
231}
232
233
234void LIB_TREE_NODE_ITEM::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
235 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
236{
237 m_Score = 1;
238
239 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : aMatchers )
240 {
241 int score = matcher->ScoreTerms( m_SearchTerms );
242
243 if( score == 0 )
244 {
245 m_Score = 0;
246 break;
247 }
248
249 m_Score += score;
250 }
251
252 if( aFilter && !(*aFilter)(*this) )
253 m_Score = 0;
254
255 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
256 child->UpdateScore( aMatchers, aFilter );
257}
258
259
261 wxString const& aDesc )
262{
263 m_Type = TYPE::LIBRARY;
264 m_Name = aName;
265 m_Desc = aDesc;
266 m_Parent = aParent;
267 m_LibId.SetLibNickname( aName );
268
269 m_SearchTerms.emplace_back( SEARCH_TERM( aName, 8 ) );
270}
271
272
274{
275 LIB_TREE_NODE_ITEM* item = new LIB_TREE_NODE_ITEM( this, aItem );
276 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
277 return *item;
278}
279
280
281void LIB_TREE_NODE_LIBRARY::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
282 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
283{
284 if( m_Children.empty() )
285 {
286 m_Score = 1;
287
288 for( const std::unique_ptr<EDA_COMBINED_MATCHER>& matcher : aMatchers )
289 {
290 int score = matcher->ScoreTerms( m_SearchTerms );
291
292 if( score == 0 )
293 {
294 m_Score = 0;
295 break;
296 }
297
298 m_Score += score;
299 }
300 }
301 else
302 {
303 m_Score = 0;
304
305 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
306 {
307 child->UpdateScore( aMatchers, aFilter );
308 m_Score = std::max( m_Score, child->m_Score );
309 }
310 }
311}
312
313
315{
316 m_Type = TYPE::ROOT;
317}
318
319
320LIB_TREE_NODE_LIBRARY& LIB_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString const& aDesc )
321{
322 LIB_TREE_NODE_LIBRARY* lib = new LIB_TREE_NODE_LIBRARY( this, aName, aDesc );
323 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( lib ) );
324 return *lib;
325}
326
327
328void LIB_TREE_NODE_ROOT::RemoveGroup( bool aRecentlyUsedGroup, bool aAlreadyPlacedGroup )
329{
330 m_Children.erase( std::remove_if( m_Children.begin(), m_Children.end(),
331 [&]( std::unique_ptr<LIB_TREE_NODE>& aNode )
332 {
333 if( aRecentlyUsedGroup && aNode->m_IsRecentlyUsedGroup )
334 return true;
335
336 if( aAlreadyPlacedGroup && aNode->m_IsAlreadyPlacedGroup )
337 return true;
338
339 return false;
340 } ),
341 m_Children.end() );
342}
343
344
346{
347 m_Children.clear();
348}
349
350
351void LIB_TREE_NODE_ROOT::UpdateScore( const std::vector<std::unique_ptr<EDA_COMBINED_MATCHER>>& aMatchers,
352 std::function<bool( LIB_TREE_NODE& aNode )>* aFilter )
353{
354 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
355 child->UpdateScore( aMatchers, aFilter );
356}
357
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:111
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition: lib_id.cpp:100
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).
Definition: lib_tree_item.h:41
virtual wxString GetUnitReference(int aUnit)
For items with units, return an identifier for unit x.
Definition: lib_tree_item.h:84
virtual wxString GetLibNickname() const =0
virtual int GetSubUnitCount() const
For items with units, return the number of units.
Definition: lib_tree_item.h:79
virtual std::vector< SEARCH_TERM > GetSearchTerms()
Definition: lib_tree_item.h:59
virtual bool HasUnitDisplayName(int aUnit)
For items with units, return true if a display name is set for x.
Definition: lib_tree_item.h:94
virtual wxString GetFootprint()
For items with footprint fields.
Definition: lib_tree_item.h:69
virtual LIB_ID GetLIB_ID() const =0
virtual wxString GetDesc()=0
virtual bool IsRoot() const
For items having aliases, IsRoot() indicates the principal item.
Definition: lib_tree_item.h:64
virtual wxString GetName() const =0
virtual int GetPinCount()
The pin count for symbols or the unique pad count for footprints.
Definition: lib_tree_item.h:74
virtual wxString GetUnitDisplayName(int aUnit)
For items with units, return a display name for unit x.
Definition: lib_tree_item.h:89
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...
Definition: lib_tree_item.h:57
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.
Model class in the component selector Model-View-Adapter (mediated MVC) architecture.
void SortNodes(bool aUseScores)
Sort child nodes quickly and recursively (IntrinsicRanks must have been set).
static bool Compare(LIB_TREE_NODE const &aNode1, LIB_TREE_NODE const &aNode2, bool aUseScores)
Compare two nodes.
enum TYPE m_Type
bool m_IsRecentlyUsedGroup
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(bool presorted=false)
Store intrinsic ranks on all children of this node.
virtual wxLocale * GetLocale()
Definition: pgm_base.h:174
#define _(s)
Abstract pattern-matching tool and implementations.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
see class PGM_BASE
A structure for storing weighted search terms.