/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Chris Pavlina * Copyright (C) 2014 Henner Zeller * Copyright (C) 2023 CERN * Copyright (C) 2014-2023 KiCad Developers, see AUTHORS.txt for contributors. * * 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 LIB_TREE_MODEL_H #define LIB_TREE_MODEL_H #include #include #include #include #include #include /** * Model class in the component selector Model-View-Adapter (mediated MVC) * architecture. The other pieces are in: * * - Adapter: LIB_TREE_MODEL_ADAPTER in common/lib_tree_model_adapter.h * - View: * - DIALOG_CHOOSE_COMPONENT in eeschema/dialogs/dialog_choose_component.h * - wxDataViewCtrl * * This model is populated from LIB_ALIASes; helper methods in the adapter * can accept entire libraries. * * Quick summary of methods used to populate this class: * - `CMP_TREE_NODE_ROOT::AddLib()` - add a new, empty library to the root * - `CMP_TREE_NODE_LIB::AddAlias()` - add an alias and its units from a * given LIB_ALIAS* * * Quick summary of methods used to drive this class: * * - `UpdateScore()` - accumulate scores recursively given a new search token * - `ResetScore()` - reset scores recursively for a new search string * - `AssignIntrinsicRanks()` - calculate and cache the initial sort order * - `SortNodes()` - recursively sort the tree by score * - `Compare()` - compare two nodes; used by `SortNodes()` * * The data in the model is meant to be accessed directly. Quick summary of * data members: * * - `Parent` - parent node, or nullptr if root * - `Children` - vector of unique_ptrs to children * - `Type` - ROOT, LIB, ALIAS, or UNIT * - `m_IntrinsicRank` - cached initial sort order * - `m_Score` - score taking into account search terms. Zero means irrelevant and * should be hidden. * - `Name` - name of the library/alias/unit, to be displayed * - `Desc` - description of the alias, to be displayed * - `m_MatchName` - Name, normalized to lowercase for matching * - `m_SearchText` - normalized composite of keywords and description * - `LibId` - the #LIB_ID this alias or unit is from, or not valid * - `Unit` - the unit number, or zero for non-units */ class LIB_TREE_NODE { public: /** * Update the score for this part. This is accumulative - it will be * called once per search term. * * @param aMatcher an EDA_COMBINED_MATCHER initialized with the search term */ virtual void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib, std::function* aFilter ) = 0; /** * Initialize scores recursively. */ virtual void ResetScore(); virtual void ForceScore( int aScore ) { m_Score = aScore; } /** * Store intrinsic ranks on all children of this node. See m_IntrinsicRank * member doc for more information. */ void AssignIntrinsicRanks( bool presorted = false ); /** * Sort child nodes quickly and recursively (IntrinsicRanks must have been set). */ void SortNodes( bool aUseScores ); /** * Compare two nodes. Returns true if aNode1 < aNode2. */ static bool Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2, bool aUseScores ); LIB_TREE_NODE(); virtual ~LIB_TREE_NODE() {} enum class TYPE { ROOT, LIBRARY, ITEM, UNIT, INVALID }; typedef std::vector> PTR_VECTOR; LIB_TREE_NODE* m_Parent; // Parent node or null PTR_VECTOR m_Children; // List of child nodes enum TYPE m_Type; // Node type /** * The rank of the item before any search terms are applied. This is * a fairly expensive sort (involving string compares) so it helps to * store the result of that sort. */ int m_IntrinsicRank; int m_Score; // The score of an item resulting from the search algorithm. bool m_Pinned; // Item should appear at top when there is no search string wxString m_Name; // Actual name of the part wxString m_Desc; // Description to be displayed wxString m_Footprint; // Footprint ID as a string (ie: the footprint field text) int m_PinCount; // Pin count from symbol, or unique pad count from footprint std::vector m_SearchTerms; /// List of weighted search terms std::map m_Fields; /// @see LIB_TREE_ITEMS::GetChooserFields LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name. int m_Unit; // Actual unit, or zero bool m_IsRoot; // Indicates if the symbol is a root symbol instead of an alias. }; /** * Node type: unit of component. */ class LIB_TREE_NODE_UNIT: public LIB_TREE_NODE { public: /** * The addresses of CMP_TREE_NODEs are used as unique IDs for the * wxDataViewModel, so don't let them be copied around. */ LIB_TREE_NODE_UNIT( LIB_TREE_NODE_UNIT const& _ ) = delete; void operator=( LIB_TREE_NODE_UNIT const& _ ) = delete; /** * Construct a unit node. * * The name of the unit will be "Unit %s", where %s is aUnit formatted * by LIB_PART::SubReference. * * @param aParent parent node, should be a CMP_TREE_NODE_ALIAS * @param aItem parent item * @param aUnit unit number */ LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem, int aUnit ); void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib, std::function* aFilter ) override; }; /** * Node type: #LIB_ID. */ class LIB_TREE_NODE_ITEM : public LIB_TREE_NODE { public: /** * The addresses of CMP_TREE_NODEs are used as unique IDs for the * wxDataViewModel, so don't let them be copied around. */ LIB_TREE_NODE_ITEM( LIB_TREE_NODE_ITEM const& _ ) = delete; void operator=( LIB_TREE_NODE_ITEM const& _ ) = delete; /** * Construct a #LIB_ID node. * * All fields will be populated from the LIB_ALIAS, including children * (unit nodes will be generated automatically). This does not keep * the pointer to the #LIB_ALIAS object because at any time, a #LIB_ALIAS * can be remove from a library which will result in an invalid pointer. * The alias must be resolved at the time of use. Anything else is a bug. * * @param aParent parent node, should be a CMP_TREE_NODE_LIB * @param aItem LIB_COMPONENT to populate the node. */ LIB_TREE_NODE_ITEM( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem ); /** * Update the node using data from a LIB_ALIAS object. */ void Update( LIB_TREE_ITEM* aItem ); /** * Perform the actual search. */ void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib, std::function* aFilter ) override; protected: /** * Add a new unit to the component and return it. * * This should not be used directly, as the constructor adds all units. */ LIB_TREE_NODE_UNIT& AddUnit( LIB_TREE_ITEM* aItem, int aUnit ); }; /** * Node type: library */ class LIB_TREE_NODE_LIBRARY : public LIB_TREE_NODE { public: /** * The addresses of CMP_TREE_NODEs are used as unique IDs for the * wxDataViewModel, so don't let them be copied around. */ LIB_TREE_NODE_LIBRARY( LIB_TREE_NODE_LIBRARY const& _ ) = delete; void operator=( LIB_TREE_NODE_LIBRARY const& _ ) = delete; /** * Construct an empty library node. * * @param aParent parent node, should be a CMP_TREE_NODE_ROOT * @param aName display name of the library * @param aDesc a description of the library */ LIB_TREE_NODE_LIBRARY( LIB_TREE_NODE* aParent, const wxString& aName, const wxString& aDesc ); /** * Construct a new alias node, add it to this library, and return it. * * @param aItem LIB_COMPONENT to provide data */ LIB_TREE_NODE_ITEM& AddItem( LIB_TREE_ITEM* aItem ); void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib, std::function* aFilter ) override; }; /** * Node type: root */ class LIB_TREE_NODE_ROOT: public LIB_TREE_NODE { public: /** * The addresses of CMP_TREE_NODEs are used as unique IDs for the * wxDataViewModel, so don't let them be copied around. */ LIB_TREE_NODE_ROOT( LIB_TREE_NODE_ROOT const& _ ) = delete; void operator=( LIB_TREE_NODE_ROOT const& _ ) = delete; /** * Construct the root node. Root nodes have no properties. */ LIB_TREE_NODE_ROOT(); /** * Construct an empty library node, add it to the root, and return it. */ LIB_TREE_NODE_LIBRARY& AddLib( wxString const& aName, wxString const& aDesc ); void UpdateScore( EDA_COMBINED_MATCHER* aMatcher, const wxString& aLib, std::function* aFilter ) override; }; #endif // LIB_TREE_MODEL_H