You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
6.8 KiB

  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. #include "property_mgr.h"
  22. #include "property.h"
  23. #include <algorithm>
  24. #include <utility>
  25. static wxString EMPTY_STRING( wxEmptyString );
  26. void PROPERTY_MANAGER::RegisterType( TYPE_ID aType, const wxString& aName )
  27. {
  28. wxASSERT( m_classNames.count( aType ) == 0 );
  29. m_classNames.emplace( aType, aName );
  30. }
  31. const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
  32. {
  33. auto it = m_classNames.find( aType );
  34. return it != m_classNames.end() ? it->second : EMPTY_STRING;
  35. }
  36. PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
  37. {
  38. if( m_dirty )
  39. const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
  40. auto it = m_classes.find( aType );
  41. if( it == m_classes.end() )
  42. return nullptr;
  43. const CLASS_DESC& classDesc = it->second;
  44. for( PROPERTY_BASE* property : classDesc.m_allProperties )
  45. {
  46. if( !aProperty.CmpNoCase( property->Name() ) )
  47. return property;
  48. }
  49. return nullptr;
  50. }
  51. const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
  52. {
  53. if( m_dirty )
  54. const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
  55. static const PROPERTY_LIST empty;
  56. auto it = m_classes.find( aType );
  57. if( it == m_classes.end() )
  58. return empty;
  59. return it->second.m_allProperties;
  60. }
  61. const void* PROPERTY_MANAGER::TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const
  62. {
  63. if( aBase == aTarget )
  64. return aSource;
  65. auto classDesc = m_classes.find( aBase );
  66. if( classDesc == m_classes.end() )
  67. return aSource;
  68. auto& converters = classDesc->second.m_typeCasts;
  69. auto converter = converters.find( aTarget );
  70. if( converter == converters.end() ) // explicit type cast not found
  71. return IsOfType( aBase, aTarget ) ? aSource : nullptr;
  72. return (*converter->second)( aSource );
  73. }
  74. void PROPERTY_MANAGER::AddProperty( PROPERTY_BASE* aProperty )
  75. {
  76. const wxString& name = aProperty->Name();
  77. TYPE_ID hash = aProperty->OwnerHash();
  78. CLASS_DESC& classDesc = getClass( hash );
  79. classDesc.m_ownProperties.emplace( name, aProperty );
  80. m_dirty = true;
  81. }
  82. void PROPERTY_MANAGER::ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew )
  83. {
  84. wxASSERT( aBase == aNew->BaseHash() );
  85. CLASS_DESC& classDesc = getClass( aNew->OwnerHash() );
  86. classDesc.m_replaced.insert( std::make_pair( aBase, aName ) );
  87. AddProperty( aNew );
  88. }
  89. void PROPERTY_MANAGER::AddTypeCast( TYPE_CAST_BASE* aCast )
  90. {
  91. TYPE_ID derivedHash = aCast->DerivedHash();
  92. CLASS_DESC& classDesc = getClass( aCast->BaseHash() );
  93. auto& typeCasts = classDesc.m_typeCasts;
  94. wxASSERT_MSG( typeCasts.count( derivedHash ) == 0, "Such converter already exists" );
  95. typeCasts.emplace( derivedHash, aCast );
  96. }
  97. void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase )
  98. {
  99. wxASSERT_MSG( aDerived != aBase, "Class cannot inherit from itself" );
  100. CLASS_DESC& derived = getClass( aDerived );
  101. CLASS_DESC& base = getClass( aBase );
  102. derived.m_bases.push_back( base );
  103. m_dirty = true;
  104. wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
  105. "You need to add a TYPE_CAST for classes inheriting from multiple bases" );
  106. }
  107. bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
  108. {
  109. if( aDerived == aBase )
  110. return true;
  111. auto derived = m_classes.find( aDerived );
  112. wxCHECK( derived != m_classes.end(), false ); // missing class description
  113. // traverse the hierarchy seeking for the base class
  114. for( auto& base : derived->second.m_bases )
  115. {
  116. if( IsOfType( base.get().m_id, aBase ) )
  117. return true;
  118. }
  119. return false;
  120. }
  121. void PROPERTY_MANAGER::Rebuild()
  122. {
  123. for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
  124. classEntry.second.rebuild();
  125. m_dirty = false;
  126. }
  127. PROPERTY_MANAGER::CLASS_DESC& PROPERTY_MANAGER::getClass( TYPE_ID aTypeId )
  128. {
  129. auto it = m_classes.find( aTypeId );
  130. if( it == m_classes.end() )
  131. tie( it, std::ignore ) = m_classes.emplace( aTypeId, CLASS_DESC( aTypeId ) );
  132. return it->second;
  133. }
  134. void PROPERTY_MANAGER::CLASS_DESC::rebuild()
  135. {
  136. PROPERTY_SET replaced( m_replaced );
  137. m_allProperties.clear();
  138. collectPropsRecur( m_allProperties, replaced );
  139. // We need to keep properties sorted to be able to use std::set_* functions
  140. sort( m_allProperties.begin(), m_allProperties.end() );
  141. }
  142. void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
  143. PROPERTY_SET& aReplaced ) const
  144. {
  145. for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
  146. aReplaced.emplace( replacedEntry );
  147. for( const std::pair<const wxString, std::unique_ptr<PROPERTY_BASE>>& prop : m_ownProperties )
  148. {
  149. PROPERTY_BASE* property = prop.second.get();
  150. // Do not store replaced properties
  151. if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 )
  152. aResult.push_back( property );
  153. }
  154. for( const std::reference_wrapper<CLASS_DESC>& base : m_bases )
  155. base.get().collectPropsRecur( aResult, aReplaced );
  156. }
  157. std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
  158. {
  159. std::vector<TYPE_ID> ids;
  160. /*
  161. for( auto& cls : m_classes )
  162. {
  163. CLASS_INFO info;
  164. for( auto prop : cls.second.m_allProperties )
  165. info.properties.push_back(prop);
  166. }
  167. */
  168. return ids;
  169. }
  170. PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses()
  171. {
  172. CLASSES_INFO rv;
  173. for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
  174. {
  175. CLASS_INFO info;
  176. info.type = classEntry.first;
  177. info.name = m_classNames[classEntry.first];
  178. for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
  179. info.properties.push_back( prop );
  180. rv.push_back( info );
  181. }
  182. return rv;
  183. }