KiCad PCB EDA Suite
property_mgr.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) 2020 CERN
5 * @author Tomasz Wlostowski <[email protected]>
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU 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
23#include <properties/property.h>
24
25#include <algorithm>
26#include <utility>
27#include <wx/wx.h>
28
29static wxString EMPTY_STRING( wxEmptyString );
30
31
32void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
33{
34 wxASSERT( m_classNames.count( aType ) == 0 );
35 m_classNames.emplace( aType, aName );
36}
37
38
39const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
40{
41 auto it = m_classNames.find( aType );
42 return it != m_classNames.end() ? it->second : EMPTY_STRING;
43}
44
45
46PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
47{
48 if( m_dirty )
49 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
50
51 auto it = m_classes.find( aType );
52
53 if( it == m_classes.end() )
54 return nullptr;
55
56 const CLASS_DESC& classDesc = it->second;
57
58 for( PROPERTY_BASE* property : classDesc.m_allProperties )
59 {
60 if( !aProperty.CmpNoCase( property->Name() ) )
61 return property;
62 }
63
64 return nullptr;
65}
66
67
69{
70 if( m_dirty )
71 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
72
73 static const PROPERTY_LIST empty;
74 auto it = m_classes.find( aType );
75
76 if( it == m_classes.end() )
77 return empty;
78
79 return it->second.m_allProperties;
80}
81
82
84{
85 if( m_dirty )
86 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
87
88 static const PROPERTY_DISPLAY_ORDER empty;
89 auto it = m_classes.find( aType );
90
91 if( it == m_classes.end() )
92 return empty;
93
94 return it->second.m_displayOrder;
95}
96
97
98const std::vector<wxString>& PROPERTY_MANAGER::GetGroupDisplayOrder( TYPE_ID aType ) const
99{
100 if( m_dirty )
101 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
102
103 static const std::vector<wxString> empty;
104 auto it = m_classes.find( aType );
105
106 if( it == m_classes.end() )
107 return empty;
108
109 return it->second.m_groupDisplayOrder;
110}
111
112
113const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const
114{
115 if( aBase == aTarget )
116 return aSource;
117
118 auto classDesc = m_classes.find( aBase );
119
120 if( classDesc == m_classes.end() )
121 return aSource;
122
123 auto& converters = classDesc->second.m_typeCasts;
124 auto converter = converters.find( aTarget );
125
126 if( converter == converters.end() ) // explicit type cast not found
127 return IsOfType( aBase, aTarget ) ? aSource : nullptr;
128
129 return (*converter->second)( aSource );
130}
131
132
133void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
134{
135 const wxString& name = aProperty->Name();
136 TYPE_ID hash = aProperty->OwnerHash();
137 CLASS_DESC& classDesc = getClass( hash );
138 classDesc.m_ownProperties.emplace( name, aProperty );
139 classDesc.m_ownDisplayOrder.emplace_back( aProperty );
140
141 aProperty->SetGroup( aGroup );
142
143 if( !classDesc.m_groups.count( aGroup ) )
144 {
145 classDesc.m_groupDisplayOrder.emplace_back( aGroup );
146 classDesc.m_groups.insert( aGroup );
147 }
148
149 m_dirty = true;
150}
151
152
153void PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew,
154 const wxString& aGroup )
155{
156 CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
157 classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
158 AddProperty( aNew, aGroup );
159}
160
161
163{
164 TYPE_ID derivedHash = aCast->DerivedHash();
165 CLASS_DESC& classDesc = getClass( aCast->BaseHash() );
166 auto& typeCasts = classDesc.m_typeCasts;
167 wxASSERT_MSG( typeCasts.count( derivedHash ) == 0, "Such converter already exists" );
168 typeCasts.emplace( derivedHash, aCast );
169}
170
171
173{
174 wxASSERT_MSG( aDerived != aBase, "Class cannot inherit from itself" );
175
176 CLASS_DESC& derived = getClass( aDerived );
177 CLASS_DESC& base = getClass( aBase );
178 derived.m_bases.push_back( base );
179 m_dirty = true;
180
181 wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
182 "You need to add a TYPE_CAST for classes inheriting from multiple bases" );
183}
184
185
186void PROPERTY_MANAGER::Mask( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName )
187{
188 wxASSERT_MSG( aDerived != aBase, "Class cannot mask from itself" );
189
190 CLASS_DESC& derived = getClass( aDerived );
191 derived.m_maskedBaseProperties.insert( std::make_pair( aBase, aName ) );
192 m_dirty = true;
193}
194
195
197 const wxString& aName,
198 std::function<bool( INSPECTABLE* )> aFunc )
199{
200 wxASSERT_MSG( aDerived != aBase, "Class cannot override from itself" );
201
202 CLASS_DESC& derived = getClass( aDerived );
203 derived.m_availabilityOverrides[std::make_pair( aBase, aName )] = aFunc;
204 m_dirty = true;
205}
206
207
209 INSPECTABLE* aItem )
210{
211 if( !aProp->Available( aItem ) )
212 return false;
213
214 CLASS_DESC& derived = getClass( aItemClass );
215
216 auto it = derived.m_availabilityOverrides.find( std::make_pair( aProp->BaseHash(),
217 aProp->Name() ) );
218
219 if( it != derived.m_availabilityOverrides.end() )
220 return it->second( aItem );
221
222 return true;
223}
224
225
226bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
227{
228 if( aDerived == aBase )
229 return true;
230
231 auto derived = m_classes.find( aDerived );
232 wxCHECK( derived != m_classes.end(), false ); // missing class description
233
234 // traverse the hierarchy seeking for the base class
235 for( auto& base : derived->second.m_bases )
236 {
237 if( IsOfType( base.get().m_id, aBase ) )
238 return true;
239 }
240
241 return false;
242}
243
244
246{
247 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
248 classEntry.second.rebuild();
249
250 m_dirty = false;
251}
252
253
255{
256 auto it = m_classes.find( aTypeId );
257
258 if( it == m_classes.end() )
259 tie( it, std::ignore ) = m_classes.emplace( aTypeId, CLASS_DESC( aTypeId ) );
260
261 return it->second;
262}
263
264
266{
267 PROPERTY_SET replaced( m_replaced );
268 m_allProperties.clear();
270 // We need to keep properties sorted to be able to use std::set_* functions
271 sort( m_allProperties.begin(), m_allProperties.end() );
272
273 std::vector<wxString> displayOrder;
274 std::set<wxString> groups;
275
276 auto collectGroups =
277 [&]( std::set<wxString>& aSet, std::vector<wxString>& aResult )
278 {
279 auto collectGroupsRecursive =
280 []( auto& aSelf, std::set<wxString>& aSetR, std::vector<wxString>& aResultR,
281 const CLASS_DESC& aClassR ) -> void
282 {
283 for( const wxString& group : aClassR.m_groupDisplayOrder )
284 {
285 if( !aSetR.count( group ) )
286 {
287 aSetR.insert( group );
288 aResultR.emplace_back( group );
289 }
290 }
291
292 for( const CLASS_DESC& base : aClassR.m_bases )
293 aSelf( aSelf, aSetR, aResultR, base );
294 };
295
296 collectGroupsRecursive( collectGroupsRecursive, aSet, aResult, *this );
297 };
298
299 // TODO(JE): This currently relies on rebuild() happening after all properties are added
300 // separate out own groups vs. all groups to fix
301 collectGroups( groups, displayOrder );
302 m_groupDisplayOrder = displayOrder;
303}
304
305
307 PROPERTY_SET& aReplaced,
308 PROPERTY_DISPLAY_ORDER& aDisplayOrder,
309 const PROPERTY_SET& aMasked ) const
310{
311 for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
312 aReplaced.emplace( replacedEntry );
313
314 /*
315 * We want to insert our own properties in forward order, but earlier than anything already in
316 * the list (which will have been added by a subclass of us)
317 */
318 int displayOrderStart = 0;
319
320 if( !aDisplayOrder.empty() )
321 {
322 int firstSoFar = std::min_element( aDisplayOrder.begin(), aDisplayOrder.end(),
323 []( const std::pair<PROPERTY_BASE*, int>& aFirst,
324 const std::pair<PROPERTY_BASE*, int>& aSecond )
325 {
326 return aFirst.second < aSecond.second;
327 } )->second;
328
329 displayOrderStart = firstSoFar - m_ownProperties.size();
330 }
331
332 int idx = 0;
333
334 for( PROPERTY_BASE* property : m_ownDisplayOrder )
335 {
336 PROPERTY_SET::key_type propertyKey = std::make_pair( property->OwnerHash(),
337 property->Name() );
338 // Do not store replaced properties
339 if( aReplaced.count( propertyKey ) )
340 continue;
341
342 // Do not store masked properties
343 if( aMasked.count( propertyKey ) )
344 continue;
345
346 aDisplayOrder[property] = displayOrderStart + idx++;
347 aResult.push_back( property );
348 }
349
350 for( const std::reference_wrapper<CLASS_DESC>& base : m_bases )
351 base.get().collectPropsRecur( aResult, aReplaced, aDisplayOrder, aMasked );
352}
353
354
355std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
356{
357 std::vector<TYPE_ID> ids;
358
359/*
360 for( auto& cls : m_classes )
361 {
362 CLASS_INFO info;
363
364 for( auto prop : cls.second.m_allProperties )
365 info.properties.push_back(prop);
366
367
368 }
369 */
370
371 return ids;
372}
373
374
376{
377 CLASSES_INFO rv;
378
379 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
380 {
382
383 info.type = classEntry.first;
384 info.name = m_classNames[classEntry.first];
385
386 for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
387 info.properties.push_back( prop );
388
389 rv.push_back( info );
390 }
391
392 return rv;
393}
const char * name
Definition: DXF_plotter.cpp:56
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
void SetGroup(const wxString &aGroup)
Definition: property.h:285
virtual size_t BaseHash() const =0
Return type-id of the Base class.
bool Available(INSPECTABLE *aObject) const
Return true if aObject offers this PROPERTY.
Definition: property.h:233
const wxString & Name() const
Definition: property.h:198
virtual size_t OwnerHash() const =0
Return type-id of the Owner class.
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
bool m_dirty
Flag indicating that the list of properties needs to be rebuild (RebuildProperties())
Definition: property_mgr.h:319
CLASSES_INFO GetAllClasses()
std::vector< CLASS_INFO > CLASSES_INFO
Definition: property_mgr.h:240
const wxString & ResolveType(TYPE_ID aType) const
Return name of a type.
const PROPERTY_LIST & GetProperties(TYPE_ID aType) const
Return all properties for a specific type.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
const PROPERTY_DISPLAY_ORDER & GetDisplayOrder(TYPE_ID aType) const
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
void AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void Rebuild()
Rebuild the list of all registered properties.
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
std::unordered_map< TYPE_ID, CLASS_DESC > m_classes
Definition: property_mgr.h:316
const void * TypeCast(const void *aSource, TYPE_ID aBase, TYPE_ID aTarget) const
Cast a type to another type.
CLASS_DESC & getClass(TYPE_ID aTypeId)
void RegisterType(TYPE_ID aType, const wxString &aName)
Associate a name with a type.
bool IsAvailableFor(TYPE_ID aItemClass, PROPERTY_BASE *aProp, INSPECTABLE *aItem)
Checks overriden availability and original availability of a property, returns false if the property ...
std::vector< TYPE_ID > GetMatchingClasses(PROPERTY_BASE *aProperty)
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
bool IsOfType(TYPE_ID aDerived, TYPE_ID aBase) const
Return true if aDerived is inherited from aBase.
void ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
std::unordered_map< TYPE_ID, wxString > m_classNames
Map of all available types.
Definition: property_mgr.h:313
const std::vector< wxString > & GetGroupDisplayOrder(TYPE_ID aType) const
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
virtual size_t BaseHash() const =0
virtual size_t DerivedHash() const =0
static bool empty(const wxTextEntryBase *aCtrl)
static wxString EMPTY_STRING(wxEmptyString)
std::vector< PROPERTY_BASE * > PROPERTY_LIST
Definition: property_mgr.h:48
std::map< PROPERTY_BASE *, int > PROPERTY_DISPLAY_ORDER
Definition: property_mgr.h:57
std::set< std::pair< size_t, wxString > > PROPERTY_SET
Definition: property_mgr.h:50
size_t TYPE_ID
Unique type identifier.
Definition: property_mgr.h:46
Returns metadata for a specific type.
Definition: property_mgr.h:256
std::vector< std::reference_wrapper< CLASS_DESC > > m_bases
Properties unique to this type (i.e. not inherited)
Definition: property_mgr.h:268
PROPERTY_SET m_replaced
Recreates the list of properties.
Definition: property_mgr.h:298
PROPERTY_SET m_maskedBaseProperties
Overrides for base class property availabilities.
Definition: property_mgr.h:277
std::vector< wxString > m_groupDisplayOrder
Non-owning list of classes's direct properties in display order.
Definition: property_mgr.h:289
std::map< wxString, std::unique_ptr< PROPERTY_BASE > > m_ownProperties
Type converters available for this type.
Definition: property_mgr.h:271
std::vector< PROPERTY_BASE * > m_ownDisplayOrder
The property groups provided by this class.
Definition: property_mgr.h:292
std::vector< PROPERTY_BASE * > m_allProperties
Compiled display order for all properties.
Definition: property_mgr.h:283
PROPERTY_DISPLAY_ORDER m_displayOrder
List of property groups provided by this class in display order.
Definition: property_mgr.h:286
std::map< TYPE_ID, std::unique_ptr< TYPE_CAST_BASE > > m_typeCasts
Properties from bases that should be masked (hidden) on this subclass.
Definition: property_mgr.h:274
void rebuild()
Traverses the class inheritance hierarchy bottom-to-top, gathering all properties available to a type...
PROPERTY_FUNCTOR_MAP m_availabilityOverrides
All properties (both unique to the type and inherited)
Definition: property_mgr.h:280
void collectPropsRecur(PROPERTY_LIST &aResult, PROPERTY_SET &aReplaced, PROPERTY_DISPLAY_ORDER &aDisplayOrder, const PROPERTY_SET &aMasked) const
std::set< wxString > m_groups
Replaced properties (TYPE_ID / name)
Definition: property_mgr.h:295