/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 CERN * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors. * * @author Tomasz Wlostowski * @author Maciej Suminski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef PROPERTY_MGR_H #define PROPERTY_MGR_H #include // Needed for stl hash extensions #include #include #include #include #include #include #include #include #include class PROPERTY_BASE; class TYPE_CAST_BASE; class ORIGIN_TRANSFORMS; class INSPECTABLE; ///< Unique type identifier using TYPE_ID = size_t; using PROPERTY_LIST = std::vector; using PROPERTY_SET = std::set>; template using PROPERTY_MAP = std::map, ValueType>; using PROPERTY_FUNCTOR_MAP = PROPERTY_MAP>; using PROPERTY_DISPLAY_ORDER = std::map; /** * Provide class metadata. Each class handled by PROPERTY_MANAGER * needs to be described using AddProperty(), AddTypeCast() and InheritsAfter() methods. * * Enum types use a dedicated property type (PROPERTY_ENUM), define its possible values * with ENUM_MAP class, then describe the type using macros: * - DECLARE_ENUM_TO_WXANY (in header files) * - IMPLEMENT_ENUM_TO_WXANY (in source files) * - ENUM_TO_WXANY (*most often used*; combines DECLARE and IMPLEMENT macros, * if there is no need to share the description using header files) * * Once all classes are described, the property list must be build using * Rebuild() method. */ class PROPERTY_MANAGER { public: static PROPERTY_MANAGER& Instance() { static PROPERTY_MANAGER pm; return pm; } /** * Associate a name with a type. * * Build a map to provide faster type look-up. * * @param aType is the type identifier (obtained using TYPE_HASH()). * @param aName is the type name. */ void RegisterType( TYPE_ID aType, const wxString& aName ); /** * Return name of a type. * * @param aType is the type identifier (obtained using TYPE_HASH()). * @return Name of the type or empty string, if not available. */ const wxString& ResolveType( TYPE_ID aType ) const; /** * Return a property for a specific type. * * @param aType is the type identifier (obtained using TYPE_HASH()). * @param aProperty is the property name used during class registration. * @return Requested property or null pointer if requested property does not exist. */ PROPERTY_BASE* GetProperty( TYPE_ID aType, const wxString& aProperty ) const; /** * Return all properties for a specific type. * * @param aType is the type identifier (obtained using TYPE_HASH()). * @return Vector storing all properties of the requested type. */ const PROPERTY_LIST& GetProperties( TYPE_ID aType ) const; const PROPERTY_DISPLAY_ORDER& GetDisplayOrder( TYPE_ID aType ) const; const std::vector& GetGroupDisplayOrder( TYPE_ID aType ) const; /** * Cast a type to another type. Used for correct type-casting of types with * multi-inheritance. Requires registration of an appropriate converter (AddTypeCast). * * @param aSource is a pointer to the casted object. * @param aBase is aSource type identifier (obtained using TYPE_HASH()). * @param aTarget is the desired type identifier (obtained using TYPE_HASH()). * @return Properly casted pointer of aTarget type. * * * @see AddTypeCast */ const void* TypeCast( const void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const; void* TypeCast( void* aSource, TYPE_ID aBase, TYPE_ID aTarget ) const { return const_cast( TypeCast( (const void*) aSource, aBase, aTarget ) ); } /** * Register a property. * Properties for a given item will be shown in the order they are added. * If a group name is supplied, the group will be created if it does not yet exists. * Groups will likewise be shown in the order they are added (so, groups first added by a base * class will appear before those of a child class). * * @param aProperty is the property to register. * @param aGroup is an optional grouping key for the property */ PROPERTY_BASE& AddProperty( PROPERTY_BASE* aProperty, const wxString& aGroup = wxEmptyString ); /** * Replace an existing property for a specific type. * * It is used to modify a property that has been inherited from a base class. * This method is used instead of AddProperty(). * * @param aBase is the base class type the delivers the original property. * @param aName is the name of the replaced property. * @param aNew is the property replacing the inherited one. * @param aGroup is the group to set for the replaced property. */ PROPERTY_BASE& ReplaceProperty( size_t aBase, const wxString& aName, PROPERTY_BASE* aNew, const wxString& aGroup = wxEmptyString ); /** * Register a type converter. Required prior TypeCast() usage. * * @param aCast is the type converter to register. */ void AddTypeCast( TYPE_CAST_BASE* aCast ); /** * Declare an inheritance relationship between types. * * @param aBase is the base type identifier (obtained using TYPE_HASH()). * @param aDerived is the derived type identifier (obtained using TYPE_HASH()). */ void InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase ); /** * Sets a base class property as masked in a derived class. Masked properties are hidden from * the list of editable properties for this class. * * @param aDerived is the type to apply the mask for. * @param aBase is the type that aName belongs to. * @param aName is the name of a property on the base class. */ void Mask( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName ); /** * Sets an override availability functor for a base class property of a given derived class. * * @param aDerived is the type to apply the mask for. * @param aBase is the type that aName belongs to. * @param aName is the name of a property on the base class. * @param aFunc is the new availability functor to apply. */ void OverrideAvailability( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName, std::function aFunc ); /** * Sets an override writeability functor for a base class property of a given derived class. * * @param aDerived is the type to apply the mask for. * @param aBase is the type that aName belongs to. * @param aName is the name of a property on the base class. * @param aFunc is the new availability functor to apply. */ void OverrideWriteability( TYPE_ID aDerived, TYPE_ID aBase, const wxString& aName, std::function aFunc ); /** * Checks overriden availability and original availability of a property, returns false * if the property is unavailable in either case. * * TODO: This isn't the cleanest API, consider how to merge with PROPERTY_BASE::Available */ bool IsAvailableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp, INSPECTABLE* aItem ); /** * Checks overriden availability and original availability of a property, returns false * if the property is unavailable in either case. * * TODO: This isn't the cleanest API, consider how to merge with PROPERTY_BASE::Writeable */ bool IsWriteableFor( TYPE_ID aItemClass, PROPERTY_BASE* aProp, INSPECTABLE* aItem ); /** * Return true if aDerived is inherited from aBase. */ bool IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const; EDA_UNITS GetUnits() const { return m_units; } void SetUnits( EDA_UNITS aUnits ) { m_units = aUnits; } ORIGIN_TRANSFORMS* GetTransforms() const { return m_originTransforms; } void SetTransforms( ORIGIN_TRANSFORMS* aTransforms ) { m_originTransforms = aTransforms; } const EDA_IU_SCALE* GetIuScale() const { return m_iuScale; } void SetIuScale( const EDA_IU_SCALE* aScale ) { m_iuScale = aScale; } /** * Rebuild the list of all registered properties. Needs to be called * once before GetProperty()/GetProperties() are used. */ void Rebuild(); struct CLASS_INFO { wxString name; TYPE_ID type; std::vector properties; }; typedef std::vector CLASSES_INFO; CLASSES_INFO GetAllClasses(); std::vector GetMatchingClasses( PROPERTY_BASE* aProperty ); private: PROPERTY_MANAGER() : m_dirty( false ), m_units( EDA_UNITS::MILLIMETRES ), m_originTransforms( nullptr ), m_iuScale( &pcbIUScale ) { } ///< Structure holding type meta-data struct CLASS_DESC { CLASS_DESC( TYPE_ID aId ) : m_id( aId ) { m_groupDisplayOrder.emplace_back( wxEmptyString ); m_groups.insert( wxEmptyString ); } ///< Unique type identifier (obtained using TYPE_HASH) const TYPE_ID m_id; ///< Types after which this type inherits std::vector> m_bases; ///< Properties unique to this type (i.e. not inherited) std::map> m_ownProperties; ///< Type converters available for this type std::map> m_typeCasts; ///< Properties from bases that should be masked (hidden) on this subclass PROPERTY_SET m_maskedBaseProperties; ///< Overrides for base class property availabilities PROPERTY_FUNCTOR_MAP m_availabilityOverrides; ///< Overrides for base class property writeable status PROPERTY_FUNCTOR_MAP m_writeabilityOverrides; ///< All properties (both unique to the type and inherited) std::vector m_allProperties; ///< Compiled display order for all properties PROPERTY_DISPLAY_ORDER m_displayOrder; ///< List of property groups provided by this class in display order std::vector m_groupDisplayOrder; ///< Non-owning list of classes's direct properties in display order std::vector m_ownDisplayOrder; ///< The property groups provided by this class std::set m_groups; ///< Replaced properties (TYPE_ID / name) PROPERTY_SET m_replaced; ///< Recreates the list of properties 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; }; ///< Returns metadata for a specific type CLASS_DESC& getClass( TYPE_ID aTypeId ); std::unordered_map m_classNames; ///< Map of all available types std::unordered_map m_classes; /// Flag indicating that the list of properties needs to be rebuild (RebuildProperties()) bool m_dirty; EDA_UNITS m_units; ORIGIN_TRANSFORMS* m_originTransforms; const EDA_IU_SCALE* m_iuScale; }; ///< Helper macro to map type hashes to names #define REGISTER_TYPE(x) PROPERTY_MANAGER::Instance().RegisterType(TYPE_HASH(x), TYPE_NAME(x)) #endif /* PROPERTY_MGR_H */