KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Tomasz Wlostowski <[email protected]>
7 * @author Maciej Suminski <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 3
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU 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 <inspectable.h>
25#include <properties/property.h>
26
27#include <algorithm>
28#include <utility>
29#include <wx/wx.h>
30
31static wxString EMPTY_STRING( wxEmptyString );
32
33
34void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
35{
36 wxASSERT( m_classNames.count( aType ) == 0 );
37 m_classNames.emplace( aType, aName );
38}
39
40
41const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
42{
43 auto it = m_classNames.find( aType );
44 return it != m_classNames.end() ? it->second : EMPTY_STRING;
45}
46
47
48PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
49{
50 if( m_dirty )
51 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
52
53 auto it = m_classes.find( aType );
54
55 if( it == m_classes.end() )
56 return nullptr;
57
58 const CLASS_DESC& classDesc = it->second;
59
60 for( PROPERTY_BASE* property : classDesc.m_allProperties )
61 {
62 if( !aProperty.CmpNoCase( property->Name() ) )
63 return property;
64 }
65
66 return nullptr;
67}
68
69
71{
72 if( m_dirty )
73 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
74
75 static const PROPERTY_LIST empty;
76 auto it = m_classes.find( aType );
77
78 if( it == m_classes.end() )
79 return empty;
80
81 return it->second.m_allProperties;
82}
83
84
86{
87 if( m_dirty )
88 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
89
90 static const PROPERTY_DISPLAY_ORDER empty;
91 auto it = m_classes.find( aType );
92
93 if( it == m_classes.end() )
94 return empty;
95
96 return it->second.m_displayOrder;
97}
98
99
100const std::vector<wxString>& PROPERTY_MANAGER::GetGroupDisplayOrder( TYPE_ID aType ) const
101{
102 if( m_dirty )
103 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
104
105 static const std::vector<wxString> empty;
106 auto it = m_classes.find( aType );
107
108 if( it == m_classes.end() )
109 return empty;
110
111 return it->second.m_groupDisplayOrder;
112}
113
114
115const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const
116{
117 if( aBase == aTarget )
118 return aSource;
119
120 auto classDesc = m_classes.find( aBase );
121
122 if( classDesc == m_classes.end() )
123 return aSource;
124
125 auto& converters = classDesc->second.m_typeCasts;
126 auto converter = converters.find( aTarget );
127
128 if( converter == converters.end() ) // explicit type cast not found
129 return IsOfType( aBase, aTarget ) ? aSource : nullptr;
130
131 return (*converter->second)( aSource );
132}
133
134
135PROPERTY_BASE& PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup )
136{
137 const wxString& name = aProperty->Name();
138 TYPE_ID hash = aProperty->OwnerHash();
139 CLASS_DESC& classDesc = getClass( hash );
140 classDesc.m_ownProperties.emplace( name, aProperty );
141 classDesc.m_ownDisplayOrder.emplace_back( aProperty );
142
143 aProperty->SetGroup( aGroup );
144
145 if( !classDesc.m_groups.count( aGroup ) )
146 {
147 classDesc.m_groupDisplayOrder.emplace_back( aGroup );
148 classDesc.m_groups.insert( aGroup );
149 }
150
151 m_dirty = true;
152 return *aProperty;
153}
154
155
156PROPERTY_BASE& PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName,
157 PROPERTY_BASE* aNew, const wxString& aGroup )
158{
159 CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
160 classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
161 return AddProperty( aNew, aGroup );
162}
163
164
166{
167 TYPE_ID derivedHash = aCast->DerivedHash();
168 CLASS_DESC& classDesc = getClass( aCast->BaseHash() );
169 auto& typeCasts = classDesc.m_typeCasts;
170 wxASSERT_MSG( typeCasts.count( derivedHash ) == 0, "Such converter already exists" );
171 typeCasts.emplace( derivedHash, aCast );
172}
173
174
176{
177 wxASSERT_MSG( aDerived != aBase, "Class cannot inherit from itself" );
178
179 CLASS_DESC& derived = getClass( aDerived );
180 CLASS_DESC& base = getClass( aBase );
181 derived.m_bases.push_back( base );
182 m_dirty = true;
183
184 wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
185 "You need to add a TYPE_CAST for classes inheriting from multiple bases" );
186}
187
188
189void PROPERTY_MANAGER::Mask( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName )
190{
191 wxASSERT_MSG( aDerived != aBase, "Class cannot mask from itself" );
192
193 CLASS_DESC& derived = getClass( aDerived );
194 derived.m_maskedBaseProperties.insert( std::make_pair( aBase, aName ) );
195 m_dirty = true;
196}
197
198
200 const wxString& aName,
201 std::function<bool( INSPECTABLE* )> aFunc )
202{
203 wxASSERT_MSG( aDerived != aBase, "Class cannot override from itself" );
204
205 CLASS_DESC& derived = getClass( aDerived );
206 derived.m_availabilityOverrides[std::make_pair( aBase, aName )] = std::move( aFunc );
207 m_dirty = true;
208}
209
210
212 const wxString& aName,
213 std::function<bool( INSPECTABLE* )> aFunc )
214{
215 wxASSERT_MSG( aDerived != aBase, "Class cannot override from itself" );
216
217 CLASS_DESC& derived = getClass( aDerived );
218 derived.m_writeabilityOverrides[std::make_pair( aBase, aName )] = std::move( aFunc );
219 m_dirty = true;
220}
221
222
224 INSPECTABLE* aItem )
225{
226 if( !aProp->Available( aItem ) )
227 return false;
228
229 CLASS_DESC& derived = getClass( aItemClass );
230
231 auto it = derived.m_availabilityOverrides.find( std::make_pair( aProp->BaseHash(),
232 aProp->Name() ) );
233
234 if( it != derived.m_availabilityOverrides.end() )
235 return it->second( aItem );
236
237 return true;
238}
239
240
242 INSPECTABLE* aItem )
243{
244 if( !aProp->Writeable( aItem ) )
245 return false;
246
247 CLASS_DESC& derived = getClass( aItemClass );
248
249 auto it = derived.m_writeabilityOverrides.find( std::make_pair( aProp->BaseHash(),
250 aProp->Name() ) );
251
252 if( it != derived.m_writeabilityOverrides.end() )
253 return it->second( aItem );
254
255 return true;
256}
257
258
259bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
260{
261 if( aDerived == aBase )
262 return true;
263
264 auto derived = m_classes.find( aDerived );
265 wxCHECK( derived != m_classes.end(), false ); // missing class description
266
267 // traverse the hierarchy seeking for the base class
268 for( auto& base : derived->second.m_bases )
269 {
270 if( IsOfType( base.get().m_id, aBase ) )
271 return true;
272 }
273
274 return false;
275}
276
277
279{
280 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
281 classEntry.second.rebuild();
282
283 m_dirty = false;
284}
285
286
288{
289 auto it = m_classes.find( aTypeId );
290
291 if( it == m_classes.end() )
292 tie( it, std::ignore ) = m_classes.emplace( aTypeId, CLASS_DESC( aTypeId ) );
293
294 return it->second;
295}
296
297
299{
300 PROPERTY_SET replaced;
301 PROPERTY_SET masked;
302 m_allProperties.clear();
304
305 // We need to keep properties sorted to be able to use std::set_* functions
306 sort( m_allProperties.begin(), m_allProperties.end() );
307
308 std::vector<wxString> displayOrder;
309 std::set<wxString> groups;
310
311 auto collectGroups =
312 [&]( std::set<wxString>& aSet, std::vector<wxString>& aResult )
313 {
314 auto collectGroupsRecursive =
315 []( auto& aSelf, std::set<wxString>& aSetR, std::vector<wxString>& aResultR,
316 const CLASS_DESC& aClassR ) -> void
317 {
318 for( const wxString& group : aClassR.m_groupDisplayOrder )
319 {
320 if( !aSetR.count( group ) )
321 {
322 aSetR.insert( group );
323 aResultR.emplace_back( group );
324 }
325 }
326
327 for( const CLASS_DESC& base : aClassR.m_bases )
328 aSelf( aSelf, aSetR, aResultR, base );
329 };
330
331 collectGroupsRecursive( collectGroupsRecursive, aSet, aResult, *this );
332 };
333
334 // TODO(JE): This currently relies on rebuild() happening after all properties are added
335 // separate out own groups vs. all groups to fix
336 collectGroups( groups, displayOrder );
337 m_groupDisplayOrder = displayOrder;
338}
339
340
342 PROPERTY_SET& aReplaced,
343 PROPERTY_DISPLAY_ORDER& aDisplayOrder,
344 PROPERTY_SET& aMasked ) const
345{
346 for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
347 aReplaced.emplace( replacedEntry );
348
349 for( const std::pair<size_t, wxString>& maskedEntry : m_maskedBaseProperties )
350 aMasked.emplace( maskedEntry );
351
352 /*
353 * We want to insert our own properties in forward order, but earlier than anything already in
354 * the list (which will have been added by a subclass of us)
355 */
356 int displayOrderStart = 0;
357
358 if( !aDisplayOrder.empty() )
359 {
360 int firstSoFar = std::min_element( aDisplayOrder.begin(), aDisplayOrder.end(),
361 []( const std::pair<PROPERTY_BASE*, int>& aFirst,
362 const std::pair<PROPERTY_BASE*, int>& aSecond )
363 {
364 return aFirst.second < aSecond.second;
365 } )->second;
366
367 displayOrderStart = firstSoFar - m_ownProperties.size();
368 }
369
370 int idx = 0;
371
372 for( PROPERTY_BASE* property : m_ownDisplayOrder )
373 {
374 PROPERTY_SET::key_type propertyKey = std::make_pair( property->OwnerHash(),
375 property->Name() );
376 // Do not store replaced properties
377 if( aReplaced.count( propertyKey ) )
378 continue;
379
380 // Do not store masked properties
381 if( aMasked.count( propertyKey ) )
382 continue;
383
384 aDisplayOrder[property] = displayOrderStart + idx++;
385 aResult.push_back( property );
386 }
387
388 // Iterate backwards so that replaced properties appear before base properties
389 for( auto it = m_bases.rbegin(); it != m_bases.rend(); ++it )
390 it->get().collectPropsRecur( aResult, aReplaced, aDisplayOrder, aMasked );
391}
392
393
394std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
395{
396 std::vector<TYPE_ID> ids;
397
398/*
399 for( auto& cls : m_classes )
400 {
401 CLASS_INFO info;
402
403 for( auto prop : cls.second.m_allProperties )
404 info.properties.push_back(prop);
405
406
407 }
408 */
409
410 return ids;
411}
412
413
415{
416 CLASSES_INFO rv;
417
418 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
419 {
421
422 info.type = classEntry.first;
423 info.name = m_classNames[classEntry.first];
424
425 for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
426 info.properties.push_back( prop );
427
428 rv.push_back( info );
429 }
430
431 return rv;
432}
433
434
436{
437 auto callListeners =
438 [&]( TYPE_ID typeId )
439 {
440 auto listeners = m_listeners.find( typeId );
441
442 if( listeners != m_listeners.end() )
443 {
444 for( const PROPERTY_LISTENER& listener : listeners->second )
445 listener( aObject, aProperty, m_managedCommit );
446 }
447 };
448
449 CLASS_DESC& objectClass = getClass( TYPE_HASH( *aObject ) );
450
451 callListeners( objectClass.m_id );
452
453 for( CLASS_DESC& superClass : objectClass.m_bases )
454 callListeners( superClass.m_id );
455}
456
457
459{
460 wxCHECK2_MSG( PROPERTY_MANAGER::Instance().m_managedCommit == nullptr,
461 return, "Can't have more than one managed commit at a time!" );
462
464}
465
466
468{
469 wxASSERT_MSG( PROPERTY_MANAGER::Instance().m_managedCommit != nullptr,
470 "Something went wrong: m_managedCommit already null!" );
471
473}
const char * name
Definition: DXF_plotter.cpp:59
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition: commit.h:74
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
PROPERTY_BASE & SetGroup(const wxString &aGroup)
Definition: property.h:328
virtual size_t BaseHash() const =0
Return type-id of the Base class.
virtual bool Writeable(INSPECTABLE *aObject) const
Definition: property.h:263
bool Available(INSPECTABLE *aObject) const
Return true if aObject offers this PROPERTY.
Definition: property.h:249
const wxString & Name() const
Definition: property.h:217
virtual size_t OwnerHash() const =0
Return type-id of the Owner class.
PROPERTY_COMMIT_HANDLER(COMMIT *aCommit)
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
bool m_dirty
Flag indicating that the list of properties needs to be rebuild (RebuildProperties())
Definition: property_mgr.h:362
CLASSES_INFO GetAllClasses()
std::vector< CLASS_INFO > CLASSES_INFO
Definition: property_mgr.h:257
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
bool IsWriteableFor(TYPE_ID aItemClass, PROPERTY_BASE *aProp, INSPECTABLE *aItem)
Checks overriden availability and original availability of a property, returns false if the property ...
void PropertyChanged(INSPECTABLE *aObject, PROPERTY_BASE *aProperty)
Callback to alert the notification system that a property has changed.
COMMIT * m_managedCommit
Definition: property_mgr.h:366
void Mask(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName)
Sets a base class property as masked in a derived class.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
PROPERTY_BASE & 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:359
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)
std::map< TYPE_ID, std::vector< PROPERTY_LISTENER > > m_listeners
Definition: property_mgr.h:364
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.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
void OverrideWriteability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override writeability functor for a base class property of a given derived class.
std::unordered_map< TYPE_ID, wxString > m_classNames
Map of all available types.
Definition: property_mgr.h:356
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)
#define TYPE_HASH(x)
Definition: property.h:71
static wxString EMPTY_STRING(wxEmptyString)
std::function< void(INSPECTABLE *, PROPERTY_BASE *, COMMIT *)> PROPERTY_LISTENER
Definition: property_mgr.h:60
std::vector< PROPERTY_BASE * > PROPERTY_LIST
Definition: property_mgr.h:49
std::map< PROPERTY_BASE *, int > PROPERTY_DISPLAY_ORDER
Definition: property_mgr.h:58
std::set< std::pair< size_t, wxString > > PROPERTY_SET
Definition: property_mgr.h:51
size_t TYPE_ID
Unique type identifier.
Definition: property_mgr.h:47
Returns metadata for a specific type.
Definition: property_mgr.h:296
std::vector< std::reference_wrapper< CLASS_DESC > > m_bases
Properties unique to this type (i.e. not inherited)
Definition: property_mgr.h:308
PROPERTY_SET m_replaced
Recreates the list of properties.
Definition: property_mgr.h:341
PROPERTY_SET m_maskedBaseProperties
Overrides for base class property availabilities.
Definition: property_mgr.h:317
std::vector< wxString > m_groupDisplayOrder
Non-owning list of classes's direct properties in display order.
Definition: property_mgr.h:332
std::map< wxString, std::unique_ptr< PROPERTY_BASE > > m_ownProperties
Type converters available for this type.
Definition: property_mgr.h:311
std::vector< PROPERTY_BASE * > m_ownDisplayOrder
The property groups provided by this class.
Definition: property_mgr.h:335
std::vector< PROPERTY_BASE * > m_allProperties
Compiled display order for all properties.
Definition: property_mgr.h:326
PROPERTY_DISPLAY_ORDER m_displayOrder
List of property groups provided by this class in display order.
Definition: property_mgr.h:329
PROPERTY_FUNCTOR_MAP m_writeabilityOverrides
All properties (both unique to the type and inherited)
Definition: property_mgr.h:323
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:314
void rebuild()
Traverses the class inheritance hierarchy bottom-to-top, gathering all properties available to a type...
void collectPropsRecur(PROPERTY_LIST &aResult, PROPERTY_SET &aReplaced, PROPERTY_DISPLAY_ORDER &aDisplayOrder, PROPERTY_SET &aMasked) const
PROPERTY_FUNCTOR_MAP m_availabilityOverrides
Overrides for base class property writeable status.
Definition: property_mgr.h:320
const TYPE_ID m_id
Types after which this type inherits.
Definition: property_mgr.h:305
std::set< wxString > m_groups
Replaced properties (TYPE_ID / name)
Definition: property_mgr.h:338