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.

250 lines
7.7 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2020 CERN
  5. * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  8. * @author Maciej Suminski <maciej.suminski@cern.ch>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 3
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License along
  21. * with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. #ifndef PROPERTY_MGR_H
  24. #define PROPERTY_MGR_H
  25. #include <core/wx_stl_compat.h> // Needed for stl hash extensions
  26. #include <wx/string.h>
  27. #include <map>
  28. #include <unordered_map>
  29. #include <set>
  30. #include <vector>
  31. #include <memory>
  32. #include <eda_units.h>
  33. class PROPERTY_BASE;
  34. class TYPE_CAST_BASE;
  35. ///< Unique type identifier
  36. using TYPE_ID = size_t;
  37. using PROPERTY_LIST = std::vector<PROPERTY_BASE*>;
  38. using PROPERTY_SET = std::set<std::pair<size_t, wxString>>;
  39. /**
  40. * Provide class metadata. Each class handled by PROPERTY_MANAGER
  41. * needs to be described using AddProperty(), AddTypeCast() and InheritsAfter() methods.
  42. *
  43. * Enum types use a dedicated property type (PROPERTY_ENUM), define its possible values
  44. * with ENUM_MAP class, then describe the type using macros:
  45. * - DECLARE_ENUM_TO_WXANY (in header files)
  46. * - IMPLEMENT_ENUM_TO_WXANY (in source files)
  47. * - ENUM_TO_WXANY (*most often used*; combines DECLARE and IMPLEMENT macros,
  48. * if there is no need to share the description using header files)
  49. *
  50. * Once all classes are described, the property list must be build using
  51. * Rebuild() method.
  52. */
  53. class PROPERTY_MANAGER
  54. {
  55. public:
  56. static PROPERTY_MANAGER& Instance()
  57. {
  58. static PROPERTY_MANAGER pm;
  59. return pm;
  60. }
  61. /**
  62. * Associate a name with a type.
  63. *
  64. * Build a map to provide faster type look-up.
  65. *
  66. * @param aType is the type identifier (obtained using TYPE_HASH()).
  67. * @param aName is the type name.
  68. */
  69. void RegisterType( TYPE_ID aType, const wxString& aName );
  70. /**
  71. * Return name of a type.
  72. *
  73. * @param aType is the type identifier (obtained using TYPE_HASH()).
  74. * @return Name of the type or empty string, if not available.
  75. */
  76. const wxString& ResolveType( TYPE_ID aType ) const;
  77. /**
  78. * Return a property for a specific type.
  79. *
  80. * @param aType is the type identifier (obtained using TYPE_HASH()).
  81. * @param aProperty is the property name used during class registration.
  82. * @return Requested property or null pointer if requested property does not exist.
  83. */
  84. PROPERTY_BASE* GetProperty( TYPE_ID aType, const wxString& aProperty ) const;
  85. /**
  86. * Return all properties for a specific type.
  87. *
  88. * @param aType is the type identifier (obtained using TYPE_HASH()).
  89. * @return Vector storing all properties of the requested type.
  90. */
  91. const PROPERTY_LIST& GetProperties( TYPE_ID aType ) const;
  92. /**
  93. * Cast a type to another type. Used for correct type-casting of types with
  94. * multi-inheritance. Requires registration of an appropriate converter (AddTypeCast).
  95. *
  96. * @param aSource is a pointer to the casted object.
  97. * @param aBase is aSource type identifier (obtained using TYPE_HASH()).
  98. * @param aTarget is the desired type identifier (obtained using TYPE_HASH()).
  99. * @return Properly casted pointer of aTarget type. *
  100. *
  101. * @see AddTypeCast
  102. */
  103. const void* TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const;
  104. void* TypeCast( void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const
  105. {
  106. return const_cast<void*>( TypeCast( (const void*) aSource, aBase, aTarget ) );
  107. }
  108. /**
  109. * Register a property.
  110. *
  111. * @param aProperty is the property to register.
  112. */
  113. void AddProperty( PROPERTY_BASE* aProperty );
  114. /**
  115. * Replace an existing property for a specific type.
  116. *
  117. * It is used to modify a property that has been inherited from a base class.
  118. * This method is used instead of AddProperty().
  119. *
  120. * @param aBase is the base class type the delivers the original property.
  121. * @param aName is the name of the replaced property.
  122. * @param aNew is the property replacing the inherited one.
  123. */
  124. void ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew );
  125. /**
  126. * Register a type converter. Required prior TypeCast() usage.
  127. *
  128. * @param aCast is the type converter to register.
  129. */
  130. void AddTypeCast( TYPE_CAST_BASE* aCast );
  131. /**
  132. * Declare an inheritance relationship between types.
  133. *
  134. * @param aBase is the base type identifier (obtained using TYPE_HASH()).
  135. * @param aDerived is the derived type identifier (obtained using TYPE_HASH()).
  136. */
  137. void InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase );
  138. /**
  139. * Return true if aDerived is inherited from aBase.
  140. */
  141. bool IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const;
  142. EDA_UNITS GetUnits() const
  143. {
  144. return m_units;
  145. }
  146. void SetUnits( EDA_UNITS aUnits )
  147. {
  148. m_units = aUnits;
  149. }
  150. /**
  151. * Rebuild the list of all registered properties. Needs to be called
  152. * once before GetProperty()/GetProperties() are used.
  153. */
  154. void Rebuild();
  155. struct CLASS_INFO
  156. {
  157. wxString name;
  158. TYPE_ID type;
  159. std::vector<PROPERTY_BASE*> properties;
  160. };
  161. typedef std::vector<CLASS_INFO> CLASSES_INFO;
  162. CLASSES_INFO GetAllClasses();
  163. std::vector<TYPE_ID> GetMatchingClasses( PROPERTY_BASE* aProperty );
  164. private:
  165. PROPERTY_MANAGER()
  166. : m_dirty( false ), m_units( EDA_UNITS::MILLIMETRES )
  167. {
  168. }
  169. ///< Structure holding type meta-data
  170. struct CLASS_DESC
  171. {
  172. CLASS_DESC( TYPE_ID aId )
  173. : m_id( aId )
  174. {
  175. }
  176. ///< Unique type identifier (obtained using TYPE_HASH)
  177. const TYPE_ID m_id;
  178. ///< Types after which this type inherits
  179. std::vector<std::reference_wrapper<CLASS_DESC>> m_bases;
  180. ///< Properties unique to this type (i.e. not inherited)
  181. std::map<wxString, std::unique_ptr<PROPERTY_BASE>> m_ownProperties;
  182. ///< Type converters available for this type
  183. std::map<TYPE_ID, std::unique_ptr<TYPE_CAST_BASE>> m_typeCasts;
  184. ///< All properties (both unique to the type and inherited)
  185. std::vector<PROPERTY_BASE*> m_allProperties;
  186. ///< Replaced properties (TYPE_ID / name)
  187. PROPERTY_SET m_replaced;
  188. ///< Recreates the list of properties
  189. void rebuild();
  190. ///< Traverses the class inheritance hierarchy bottom-to-top, gathering
  191. ///< all properties available to a type
  192. void collectPropsRecur( PROPERTY_LIST& aResult, PROPERTY_SET& aReplaced ) const;
  193. };
  194. ///< Returns metadata for a specific type
  195. CLASS_DESC& getClass( TYPE_ID aTypeId );
  196. std::unordered_map<TYPE_ID, wxString> m_classNames;
  197. ///< Map of all available types
  198. std::unordered_map<TYPE_ID, CLASS_DESC> m_classes;
  199. /// Flag indicating that the list of properties needs to be rebuild (RebuildProperties())
  200. bool m_dirty;
  201. EDA_UNITS m_units;
  202. };
  203. ///< Helper macro to map type hashes to names
  204. #define REGISTER_TYPE(x) PROPERTY_MANAGER::Instance().RegisterType(TYPE_HASH(x), TYPE_NAME(x))
  205. #endif /* PROPERTY_MGR_H */