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
22#include "property_mgr.h"
23#include "property.h"
24
25#include <algorithm>
26#include <utility>
27
28static wxString EMPTY_STRING( wxEmptyString );
29
30
31void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
32{
33 wxASSERT( m_classNames.count( aType ) == 0 );
34 m_classNames.emplace( aType, aName );
35}
36
37
38const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
39{
40 auto it = m_classNames.find( aType );
41 return it != m_classNames.end() ? it->second : EMPTY_STRING;
42}
43
44
45PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
46{
47 if( m_dirty )
48 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
49
50 auto it = m_classes.find( aType );
51
52 if( it == m_classes.end() )
53 return nullptr;
54
55 const CLASS_DESC& classDesc = it->second;
56
57 for( PROPERTY_BASE* property : classDesc.m_allProperties )
58 {
59 if( !aProperty.CmpNoCase( property->Name() ) )
60 return property;
61 }
62
63 return nullptr;
64}
65
66
68{
69 if( m_dirty )
70 const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
71
72 static const PROPERTY_LIST empty;
73 auto it = m_classes.find( aType );
74
75 if( it == m_classes.end() )
76 return empty;
77
78 return it->second.m_allProperties;
79}
80
81
82const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const
83{
84 if( aBase == aTarget )
85 return aSource;
86
87 auto classDesc = m_classes.find( aBase );
88
89 if( classDesc == m_classes.end() )
90 return aSource;
91
92 auto& converters = classDesc->second.m_typeCasts;
93 auto converter = converters.find( aTarget );
94
95 if( converter == converters.end() ) // explicit type cast not found
96 return IsOfType( aBase, aTarget ) ? aSource : nullptr;
97
98 return (*converter->second)( aSource );
99}
100
101
103{
104 const wxString& name = aProperty->Name();
105 TYPE_ID hash = aProperty->OwnerHash();
106 CLASS_DESC& classDesc = getClass( hash );
107 classDesc.m_ownProperties.emplace( name, aProperty );
108 m_dirty = true;
109}
110
111
112void PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew )
113{
114 wxASSERT( aBase == aNew->BaseHash() );
115 CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
116 classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
117 AddProperty( aNew );
118}
119
120
122{
123 TYPE_ID derivedHash = aCast->DerivedHash();
124 CLASS_DESC& classDesc = getClass( aCast->BaseHash() );
125 auto& typeCasts = classDesc.m_typeCasts;
126 wxASSERT_MSG( typeCasts.count( derivedHash ) == 0, "Such converter already exists" );
127 typeCasts.emplace( derivedHash, aCast );
128}
129
130
132{
133 wxASSERT_MSG( aDerived != aBase, "Class cannot inherit from itself" );
134
135 CLASS_DESC& derived = getClass( aDerived );
136 CLASS_DESC& base = getClass( aBase );
137 derived.m_bases.push_back( base );
138 m_dirty = true;
139
140 wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
141 "You need to add a TYPE_CAST for classes inheriting from multiple bases" );
142}
143
144
145bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
146{
147 if( aDerived == aBase )
148 return true;
149
150 auto derived = m_classes.find( aDerived );
151 wxCHECK( derived != m_classes.end(), false ); // missing class description
152
153 // traverse the hierarchy seeking for the base class
154 for( auto& base : derived->second.m_bases )
155 {
156 if( IsOfType( base.get().m_id, aBase ) )
157 return true;
158 }
159
160 return false;
161}
162
163
165{
166 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
167 classEntry.second.rebuild();
168
169 m_dirty = false;
170}
171
172
174{
175 auto it = m_classes.find( aTypeId );
176
177 if( it == m_classes.end() )
178 tie( it, std::ignore ) = m_classes.emplace( aTypeId, CLASS_DESC( aTypeId ) );
179
180 return it->second;
181}
182
183
185{
186 PROPERTY_SET replaced( m_replaced );
187 m_allProperties.clear();
189 // We need to keep properties sorted to be able to use std::set_* functions
190 sort( m_allProperties.begin(), m_allProperties.end() );
191}
192
193
195 PROPERTY_SET& aReplaced ) const
196{
197 for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
198 aReplaced.emplace( replacedEntry );
199
200 for( const std::pair<const wxString, std::unique_ptr<PROPERTY_BASE>>& prop : m_ownProperties )
201 {
202 PROPERTY_BASE* property = prop.second.get();
203
204 // Do not store replaced properties
205 if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 )
206 aResult.push_back( property );
207 }
208
209 for( const std::reference_wrapper<CLASS_DESC>& base : m_bases )
210 base.get().collectPropsRecur( aResult, aReplaced );
211}
212
213
214std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
215{
216 std::vector<TYPE_ID> ids;
217
218/*
219 for( auto& cls : m_classes )
220 {
221 CLASS_INFO info;
222
223 for( auto prop : cls.second.m_allProperties )
224 info.properties.push_back(prop);
225
226
227 }
228 */
229
230 return ids;
231}
232
233
235{
236 CLASSES_INFO rv;
237
238 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
239 {
241
242 info.type = classEntry.first;
243 info.name = m_classNames[classEntry.first];
244
245 for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
246 info.properties.push_back( prop );
247
248 rv.push_back( info );
249 }
250
251 return rv;
252}
const char * name
Definition: DXF_plotter.cpp:56
virtual size_t BaseHash() const =0
Return type-id of the Base class.
const wxString & Name() const
Definition: property.h:191
virtual size_t OwnerHash() const =0
Return type-id of the Owner class.
T get(const void *aObject) const
Definition: property.h:270
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:63
bool m_dirty
Flag indicating that the list of properties needs to be rebuild (RebuildProperties())
Definition: property_mgr.h:241
CLASSES_INFO GetAllClasses()
void AddProperty(PROPERTY_BASE *aProperty)
Register a property.
std::vector< CLASS_INFO > CLASSES_INFO
Definition: property_mgr.h:186
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.
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.
void ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew)
Replace an existing property for a specific type.
std::unordered_map< TYPE_ID, CLASS_DESC > m_classes
Definition: property_mgr.h:238
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.
std::vector< TYPE_ID > GetMatchingClasses(PROPERTY_BASE *aProperty)
bool IsOfType(TYPE_ID aDerived, TYPE_ID aBase) const
Return true if aDerived is inherited from aBase.
std::unordered_map< TYPE_ID, wxString > m_classNames
Map of all available types.
Definition: property_mgr.h:235
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:44
std::set< std::pair< size_t, wxString > > PROPERTY_SET
Definition: property_mgr.h:46
size_t TYPE_ID
Unique type identifier.
Definition: property_mgr.h:42
Returns metadata for a specific type.
Definition: property_mgr.h:200
std::vector< std::reference_wrapper< CLASS_DESC > > m_bases
Properties unique to this type (i.e. not inherited)
Definition: property_mgr.h:210
PROPERTY_SET m_replaced
Recreates the list of properties.
Definition: property_mgr.h:222
std::map< wxString, std::unique_ptr< PROPERTY_BASE > > m_ownProperties
Type converters available for this type.
Definition: property_mgr.h:213
std::vector< PROPERTY_BASE * > m_allProperties
Replaced properties (TYPE_ID / name)
Definition: property_mgr.h:219
void collectPropsRecur(PROPERTY_LIST &aResult, PROPERTY_SET &aReplaced) const
std::map< TYPE_ID, std::unique_ptr< TYPE_CAST_BASE > > m_typeCasts
All properties (both unique to the type and inherited)
Definition: property_mgr.h:216
void rebuild()
Traverses the class inheritance hierarchy bottom-to-top, gathering all properties available to a type...