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 *lib_tree_model
4 * Copyright (C) 2017 Chris Pavlina <[email protected]>
5 * Copyright (C) 2014 Henner Zeller <[email protected]>
6 * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <lib_tree_model.h>
23
24#include <algorithm>
25#include <eda_pattern_match.h>
26#include <lib_tree_item.h>
27#include <pgm_base.h>
28#include <string_utils.h>
29
30// Each node gets this lowest score initially, without any matches applied. Matches will then
31// increase this score. This way, an empty search string will result in all components being
32// displayed as they have the minimum score. However, in that case, we avoid expanding all the
33// nodes asd the result is very unspecific.
34static const unsigned kLowestDefaultScore = 1;
35
36
38{
39 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
40 child->ResetScore();
41
43}
44
45
47{
48 std::vector<LIB_TREE_NODE*> sort_buf;
49
50 if( presorted )
51 {
52 int max = m_Children.size() - 1;
53
54 for( int i = 0; i <= max; ++i )
55 m_Children[i]->m_IntrinsicRank = max - i;
56 }
57 else
58 {
59 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
60 sort_buf.push_back( child.get() );
61
62 std::sort( sort_buf.begin(), sort_buf.end(),
63 []( LIB_TREE_NODE* a, LIB_TREE_NODE* b ) -> bool
64 {
65 return StrNumCmp( a->m_Name, b->m_Name, true ) > 0;
66 } );
67
68 for( int i = 0; i < (int) sort_buf.size(); ++i )
69 sort_buf[i]->m_IntrinsicRank = i;
70 }
71}
72
73
74void LIB_TREE_NODE::SortNodes( bool aUseScores )
75{
76 std::sort( m_Children.begin(), m_Children.end(),
77 [&]( std::unique_ptr<LIB_TREE_NODE>& a, std::unique_ptr<LIB_TREE_NODE>& b )
78 {
79 return Compare( *a, *b, aUseScores );
80 } );
81
82 for( std::unique_ptr<LIB_TREE_NODE>& node: m_Children )
83 node->SortNodes( aUseScores );
84}
85
86
87bool LIB_TREE_NODE::Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2,
88 bool aUseScores )
89{
90 if( aNode1.m_Type != aNode2.m_Type )
91 return aNode1.m_Type < aNode2.m_Type;
92
93 // Recently used sorts at top
94 if( aNode1.m_Name.StartsWith( wxT( "-- " ) ) )
95 {
96 if( aNode2.m_Name.StartsWith( wxT( "-- " ) ) )
97 {
98 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
99 }
100 else
101 {
102 return true;
103 }
104 }
105 else if( aNode2.m_Name.StartsWith( wxT( "-- " ) ) )
106 {
107 return false;
108 }
109
110 // Pinned nodes go next
111 if( aNode1.m_Pinned && !aNode2.m_Pinned )
112 return true;
113 else if( aNode2.m_Pinned && !aNode1.m_Pinned )
114 return false;
115
116 if( aUseScores && aNode1.m_Score != aNode2.m_Score )
117 return aNode1.m_Score > aNode2.m_Score;
118
119 if( aNode1.m_IntrinsicRank != aNode2.m_IntrinsicRank )
120 return aNode1.m_IntrinsicRank > aNode2.m_IntrinsicRank;
121
122 return reinterpret_cast<const void*>( &aNode1 ) < reinterpret_cast<const void*>( &aNode2 );
123}
124
125
127 : m_Parent( nullptr ),
128 m_Type( INVALID ),
129 m_IntrinsicRank( 0 ),
130 m_Score( kLowestDefaultScore ),
131 m_Pinned( false ),
132 m_Unit( 0 ),
133 m_IsRoot( false )
134{}
135
136
138{
139 static void* locale = nullptr;
140 static wxString namePrefix;
141
142 // Fetching translations can take a surprising amount of time when loading libraries,
143 // so only do it when necessary.
144 if( Pgm().GetLocale() != locale )
145 {
146 namePrefix = _( "Unit" );
147 locale = Pgm().GetLocale();
148 }
149
150 m_Parent = aParent;
151 m_Type = UNIT;
152
153 m_Unit = aUnit;
154 m_LibId = aParent->m_LibId;
155
156 m_Name = namePrefix + " " + aItem->GetUnitReference( aUnit );
157
158 if( aItem->HasUnitDisplayName( aUnit ) )
159 m_Desc = aItem->GetUnitDisplayName( aUnit );
160 else
161 m_Desc = wxEmptyString;
162
163 m_IntrinsicRank = -aUnit;
164}
165
166
168{
169 m_Type = LIBID;
170 m_Parent = aParent;
171
173 m_LibId.SetLibItemName( aItem->GetName() );
174
175 m_Name = aItem->GetName();
176 m_Desc = aItem->GetDescription();
177 m_Footprint = aItem->GetFootprint();
178
179 aItem->GetChooserFields( m_Fields );
180
181 m_SearchTerms = aItem->GetSearchTerms();
182
183 m_IsRoot = aItem->IsRoot();
184
185 if( aItem->GetUnitCount() > 1 )
186 {
187 for( int u = 1; u <= aItem->GetUnitCount(); ++u )
188 AddUnit( aItem, u );
189 }
190}
191
192
194{
195 LIB_TREE_NODE_UNIT* unit = new LIB_TREE_NODE_UNIT( this, aItem, aUnit );
196 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( unit ) );
197 return *unit;
198}
199
200
202{
204 m_LibId.SetLibItemName( aItem->GetName() );
205
206 m_Name = aItem->GetName();
207 m_Desc = aItem->GetDescription();
208
209 aItem->GetChooserFields( m_Fields );
210
211 m_SearchTerms = aItem->GetSearchTerms();
212
213 m_IsRoot = aItem->IsRoot();
214 m_Children.clear();
215
216 for( int u = 1; u <= aItem->GetUnitCount(); ++u )
217 AddUnit( aItem, u );
218}
219
220
221void LIB_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
222{
223 if( m_Score <= 0 )
224 return; // Leaf nodes without scores are out of the game.
225
226 if( !aLib.IsEmpty() && m_Parent->m_Name.Lower() != aLib )
227 {
228 m_Score = 0;
229 return;
230 }
231
232 m_Score = aMatcher.ScoreTerms( m_SearchTerms );
233}
234
235
237 wxString const& aDesc )
238{
239 m_Type = LIB;
240 m_Name = aName;
241 m_Desc = aDesc;
242 m_Parent = aParent;
243 m_LibId.SetLibNickname( aName );
244}
245
246
248{
249 LIB_TREE_NODE_LIB_ID* item = new LIB_TREE_NODE_LIB_ID( this, aItem );
250 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( item ) );
251 return *item;
252}
253
254
255void LIB_TREE_NODE_LIB::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
256{
257 m_Score = 0;
258
259 // We need to score leaf nodes, which are usually (but not always) children.
260
261 if( m_Children.size() )
262 {
263 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
264 {
265 child->UpdateScore( aMatcher, aLib );
266 m_Score = std::max( m_Score, child->m_Score );
267 }
268 }
269 else
270 {
271 // No children; we are a leaf.
272
273 m_Score = aMatcher.ScoreTerms( m_SearchTerms );
274 }
275}
276
277
279{
280 m_Type = ROOT;
281}
282
283
284LIB_TREE_NODE_LIB& LIB_TREE_NODE_ROOT::AddLib( wxString const& aName, wxString const& aDesc )
285{
286 LIB_TREE_NODE_LIB* lib = new LIB_TREE_NODE_LIB( this, aName, aDesc );
287 m_Children.push_back( std::unique_ptr<LIB_TREE_NODE>( lib ) );
288 return *lib;
289}
290
291
292void LIB_TREE_NODE_ROOT::UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib )
293{
294 for( std::unique_ptr<LIB_TREE_NODE>& child: m_Children )
295 child->UpdateScore( aMatcher, aLib );
296}
297
int ScoreTerms(std::vector< SEARCH_TERM > &aWeightedTerms)
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:109
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:98
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:79
virtual wxString GetLibNickname() const =0
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:89
virtual wxString GetFootprint()
For items with footprint fields.
Definition: lib_tree_item.h:69
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 wxString GetDescription()=0
virtual LIB_ID GetLibId() const =0
virtual int GetUnitCount() const
For items with units, return the number of units.
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:84
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.
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.
LIB_TREE_NODE_LIB_ID(LIB_TREE_NODE_LIB_ID const &_)=delete
The addresses of CMP_TREE_NODEs are used as unique IDs for the wxDataViewModel, so don't let them be ...
virtual void UpdateScore(EDA_COMBINED_MATCHER &aMatcher, const wxString &aLib) override
Perform the actual search.
Node type: library.
LIB_TREE_NODE_LIB_ID & AddItem(LIB_TREE_ITEM *aItem)
Construct a new alias node, add it to this library, and return it.
LIB_TREE_NODE_LIB(LIB_TREE_NODE_LIB const &_)=delete
The addresses of CMP_TREE_NODEs are used as unique IDs for the wxDataViewModel, so don't let them be ...
virtual void UpdateScore(EDA_COMBINED_MATCHER &aMatcher, const wxString &aLib) override
Update the score for this part.
virtual void UpdateScore(EDA_COMBINED_MATCHER &aMatcher, const wxString &aLib) override
Update the score for this part.
LIB_TREE_NODE_ROOT()
Construct the root node.
LIB_TREE_NODE_LIB & AddLib(wxString const &aName, wxString const &aDesc)
Construct an empty library node, add it to the root, and return it.
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 ...
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
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
void ResetScore()
Initialize score to kLowestDefaultScore, recursively.
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.
#define _(s)
Abstract pattern-matching tool and implementations.
@ INVALID
Definition: kiface_ids.h:32
static const unsigned kLowestDefaultScore
see class PGM_BASE
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:115