1 /* 2 * This program source code file is part of KiCad, a free EDA CAD application. 3 * 4 * Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com> 5 * Copyright (C) 2014 Henner Zeller <h.zeller@acm.org> 6 * Copyright (C) 2014-2021 KiCad Developers, see AUTHORS.txt for contributors. 7 * 8 * This program is free software: you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation, either version 3 of the License, or (at your 11 * option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * 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 #ifndef LIB_TREE_MODEL_H 23 #define LIB_TREE_MODEL_H 24 25 #include <vector> 26 #include <memory> 27 #include <wx/string.h> 28 #include <lib_tree_item.h> 29 30 31 class EDA_COMBINED_MATCHER; 32 33 34 /** 35 * Model class in the component selector Model-View-Adapter (mediated MVC) 36 * architecture. The other pieces are in: 37 * 38 * - Adapter: LIB_TREE_MODEL_ADAPTER in common/lib_tree_model_adapter.h 39 * - View: 40 * - DIALOG_CHOOSE_COMPONENT in eeschema/dialogs/dialog_choose_component.h 41 * - wxDataViewCtrl 42 * 43 * This model is populated from LIB_ALIASes; helper methods in the adapter 44 * can accept entire libraries. 45 * 46 * Quick summary of methods used to populate this class: 47 * - `CMP_TREE_NODE_ROOT::AddLib()` - add a new, empty library to the root 48 * - `CMP_TREE_NODE_LIB::AddAlias()` - add an alias and its units from a 49 * given LIB_ALIAS* 50 * 51 * Quick summary of methods used to drive this class: 52 * 53 * - `UpdateScore()` - accumulate scores recursively given a new search token 54 * - `ResetScore()` - reset scores recursively for a new search string 55 * - `AssignIntrinsicRanks()` - calculate and cache the initial sort order 56 * - `SortNodes()` - recursively sort the tree by score 57 * - `Compare()` - compare two nodes; used by `SortNodes()` 58 * 59 * The data in the model is meant to be accessed directly. Quick summary of 60 * data members: 61 * 62 * - `Parent` - parent node, or nullptr if root 63 * - `Children` - vector of unique_ptrs to children 64 * - `Type` - ROOT, LIB, ALIAS, or UNIT 65 * - `m_IntrinsicRank` - cached initial sort order 66 * - `m_Score` - score taking into account search terms. Zero means irrelevant and 67 * should be hidden. 68 * - `Name` - name of the library/alias/unit, to be displayed 69 * - `Desc` - description of the alias, to be displayed 70 * - `m_MatchName` - Name, normalized to lowercase for matching 71 * - `m_SearchText` - normalized composite of keywords and description 72 * - `LibId` - the #LIB_ID this alias or unit is from, or not valid 73 * - `Unit` - the unit number, or zero for non-units 74 */ 75 class LIB_TREE_NODE 76 { 77 public: 78 /** 79 * Update the score for this part. This is accumulative - it will be 80 * called once per search term. 81 * 82 * @param aMatcher an EDA_COMBINED_MATCHER initialized with the search term 83 */ 84 virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) = 0; 85 86 /** 87 * Initialize score to kLowestDefaultScore, recursively. 88 */ 89 void ResetScore(); 90 91 /** 92 * Store intrinsic ranks on all children of this node. See m_IntrinsicRank 93 * member doc for more information. 94 */ 95 void AssignIntrinsicRanks( bool presorted = false ); 96 97 /** 98 * Sort child nodes quickly and recursively (IntrinsicRanks must have been set). 99 */ 100 void SortNodes(); 101 102 /** 103 * Compare two nodes. Returns negative if aNode1 < aNode2, zero if aNode1 == 104 * aNode2, or positive if aNode1 > aNode2. 105 */ 106 static int Compare( LIB_TREE_NODE const& aNode1, LIB_TREE_NODE const& aNode2 ); 107 108 LIB_TREE_NODE(); ~LIB_TREE_NODE()109 virtual ~LIB_TREE_NODE() {} 110 111 enum TYPE { 112 ROOT, LIB, LIBID, UNIT, INVALID 113 }; 114 115 typedef std::vector<std::unique_ptr<LIB_TREE_NODE>> PTR_VECTOR; 116 117 LIB_TREE_NODE* m_Parent; // Parent node or null 118 PTR_VECTOR m_Children; // List of child nodes 119 enum TYPE m_Type; // Node type 120 121 /** 122 * The rank of the item before any search terms are applied. This is 123 * a fairly expensive sort (involving string compares) so it helps to 124 * store the result of that sort. 125 */ 126 int m_IntrinsicRank; 127 128 int m_Score; // The score of an item resulting from the search algorithm. 129 bool m_Pinned; // Item should appear at top when there is no search string 130 131 wxString m_Name; // Actual name of the part 132 wxString m_Desc; // Description to be displayed 133 wxString m_MatchName; // Normalized name for matching 134 wxString m_SearchText; // Descriptive text to search 135 bool m_Normalized; // Support for lazy normalization. 136 137 138 LIB_ID m_LibId; // LIB_ID determined by the parent library nickname and alias name. 139 int m_Unit; // Actual unit, or zero 140 bool m_IsRoot; // Indicates if the symbol is a root symbol instead of an alias. 141 }; 142 143 144 /** 145 * Node type: unit of component. 146 */ 147 class LIB_TREE_NODE_UNIT: public LIB_TREE_NODE 148 { 149 public: 150 /** 151 * The addresses of CMP_TREE_NODEs are used as unique IDs for the 152 * wxDataViewModel, so don't let them be copied around. 153 */ 154 LIB_TREE_NODE_UNIT( LIB_TREE_NODE_UNIT const& _ ) = delete; 155 void operator=( LIB_TREE_NODE_UNIT const& _ ) = delete; 156 157 /** 158 * Construct a unit node. 159 * 160 * The name of the unit will be "Unit %s", where %s is aUnit formatted 161 * by LIB_PART::SubReference. 162 * 163 * @param aParent parent node, should be a CMP_TREE_NODE_ALIAS 164 * @param aItem parent item 165 * @param aUnit unit number 166 */ 167 LIB_TREE_NODE_UNIT( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem, int aUnit ); 168 169 170 /** 171 * Do nothing, units just take the parent's score 172 */ UpdateScore(EDA_COMBINED_MATCHER & aMatcher,const wxString & aLib)173 virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override {} 174 }; 175 176 177 /** 178 * Node type: #LIB_ID. 179 */ 180 class LIB_TREE_NODE_LIB_ID: public LIB_TREE_NODE 181 { 182 public: 183 /** 184 * The addresses of CMP_TREE_NODEs are used as unique IDs for the 185 * wxDataViewModel, so don't let them be copied around. 186 */ 187 LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE_LIB_ID const& _ ) = delete; 188 void operator=( LIB_TREE_NODE_LIB_ID const& _ ) = delete; 189 190 /** 191 * Construct a #LIB_ID node. 192 * 193 * All fields will be populated from the LIB_ALIAS, including children 194 * (unit nodes will be generated automatically). This does not keep 195 * the pointer to the #LIB_ALIAS object because at any time, a #LIB_ALIAS 196 * can be remove from a library which will result in an invalid pointer. 197 * The alias must be resolved at the time of use. Anything else is a bug. 198 * 199 * @param aParent parent node, should be a CMP_TREE_NODE_LIB 200 * @param aItem LIB_COMPONENT to populate the node. 201 */ 202 LIB_TREE_NODE_LIB_ID( LIB_TREE_NODE* aParent, LIB_TREE_ITEM* aItem ); 203 204 /** 205 * Update the node using data from a LIB_ALIAS object. 206 */ 207 void Update( LIB_TREE_ITEM* aItem ); 208 209 /** 210 * Perform the actual search. 211 */ 212 virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override; 213 214 protected: 215 /** 216 * Add a new unit to the component and return it. 217 * 218 * This should not be used directly, as the constructor adds all units. 219 */ 220 LIB_TREE_NODE_UNIT& AddUnit( LIB_TREE_ITEM* aItem, int aUnit ); 221 }; 222 223 224 /** 225 * Node type: library 226 */ 227 class LIB_TREE_NODE_LIB: public LIB_TREE_NODE 228 { 229 public: 230 /** 231 * The addresses of CMP_TREE_NODEs are used as unique IDs for the 232 * wxDataViewModel, so don't let them be copied around. 233 */ 234 LIB_TREE_NODE_LIB( LIB_TREE_NODE_LIB const& _ ) = delete; 235 void operator=( LIB_TREE_NODE_LIB const& _ ) = delete; 236 237 /** 238 * Construct an empty library node. 239 * 240 * @param aParent parent node, should be a CMP_TREE_NODE_ROOT 241 * @param aName display name of the library 242 * @param aDesc a description of the library 243 */ 244 LIB_TREE_NODE_LIB( LIB_TREE_NODE* aParent, const wxString& aName, const wxString& aDesc ); 245 246 /** 247 * Construct a new alias node, add it to this library, and return it. 248 * 249 * @param aItem LIB_COMPONENT to provide data 250 */ 251 LIB_TREE_NODE_LIB_ID& AddItem( LIB_TREE_ITEM* aItem ); 252 253 virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override; 254 }; 255 256 257 /** 258 * Node type: root 259 */ 260 class LIB_TREE_NODE_ROOT: public LIB_TREE_NODE 261 { 262 public: 263 /** 264 * The addresses of CMP_TREE_NODEs are used as unique IDs for the 265 * wxDataViewModel, so don't let them be copied around. 266 */ 267 LIB_TREE_NODE_ROOT( LIB_TREE_NODE_ROOT const& _ ) = delete; 268 void operator=( LIB_TREE_NODE_ROOT const& _ ) = delete; 269 270 /** 271 * Construct the root node. Root nodes have no properties. 272 */ 273 LIB_TREE_NODE_ROOT(); 274 275 /** 276 * Construct an empty library node, add it to the root, and return it. 277 */ 278 LIB_TREE_NODE_LIB& AddLib( wxString const& aName, wxString const& aDesc ); 279 280 virtual void UpdateScore( EDA_COMBINED_MATCHER& aMatcher, const wxString& aLib ) override; 281 }; 282 283 284 #endif // LIB_TREE_MODEL_H 285