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 <tomasz.wlostowski@cern.ch>
6 * @author Maciej Suminski <maciej.suminski@cern.ch>
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
28 static wxString EMPTY_STRING( wxEmptyString );
29
30
RegisterType(TYPE_ID aType,const wxString & aName)31 void 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
ResolveType(TYPE_ID aType) const38 const 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
GetProperty(TYPE_ID aType,const wxString & aProperty) const45 PROPERTY_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
GetProperties(TYPE_ID aType) const67 const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
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
TypeCast(const void * aSource,TYPE_ID aBase,TYPE_ID aTarget) const82 const 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
AddProperty(PROPERTY_BASE * aProperty)102 void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty )
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
ReplaceProperty(size_t aBase,const wxString & aName,PROPERTY_BASE * aNew)112 void 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
AddTypeCast(TYPE_CAST_BASE * aCast)121 void PROPERTY_MANAGER::AddTypeCast( TYPE_CAST_BASE* aCast )
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
InheritsAfter(TYPE_ID aDerived,TYPE_ID aBase)131 void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase )
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
IsOfType(TYPE_ID aDerived,TYPE_ID aBase) const145 bool 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
Rebuild()164 void PROPERTY_MANAGER::Rebuild()
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
getClass(TYPE_ID aTypeId)173 PROPERTY_MANAGER::CLASS_DESC& PROPERTY_MANAGER::getClass( TYPE_ID aTypeId )
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
rebuild()184 void PROPERTY_MANAGER::CLASS_DESC::rebuild()
185 {
186 PROPERTY_SET replaced( m_replaced );
187 m_allProperties.clear();
188 collectPropsRecur( m_allProperties, replaced );
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
collectPropsRecur(PROPERTY_LIST & aResult,PROPERTY_SET & aReplaced) const194 void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
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
GetMatchingClasses(PROPERTY_BASE * aProperty)214 std::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
GetAllClasses()234 PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses()
235 {
236 CLASSES_INFO rv;
237
238 for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
239 {
240 CLASS_INFO info;
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 }
253