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.

412 lines
14 KiB

  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. #ifndef LIB_TREE_MODEL_ADAPTER_H
  22. #define LIB_TREE_MODEL_ADAPTER_H
  23. #include <lib_id.h>
  24. #include <lib_tree_model.h>
  25. #include <wx/hashmap.h>
  26. #include <wx/dataview.h>
  27. #include <wx/headerctrl.h>
  28. #include <vector>
  29. #include <functional>
  30. #include <set>
  31. /**
  32. * Adapter class in the symbol selector Model-View-Adapter (mediated MVC)
  33. * architecture. The other pieces are in:
  34. *
  35. * - Model: SYM_TREE_NODE and descendants in eeschema/cmp_tree_model.h
  36. * - View:
  37. * - DIALOG_CHOOSE_COMPONENT in eeschema/dialogs/dialog_choose_component.h
  38. * - wxDataViewCtrl
  39. *
  40. * This adapter presents the interface specified by wxDataViewModel to the
  41. * wxDataViewCtrl:
  42. *
  43. * +---+ +------------------+
  44. * +---+ Generates | A | | VIEW |
  45. * | M | from libs | D | wxDataViewModel |------------------|
  46. * | O | <---------- | A | <------------------> | wxDataViewCtrl |
  47. * | D | | P | |------------------|
  48. * | E | <---------> | T | <------------------- | wxTextCtrl |
  49. * | L | UpdateScore | E | UpdateSearchString() |------------------|
  50. * +---+ | R | | |
  51. * +---+ +------------------+
  52. *
  53. * Because this adapter is a wxDataViewModel, it is reference-counted by
  54. * wxObject. To ensure this interface is used correctly, the constructor
  55. * is private; LIB_TREE_MODEL_ADAPTER should be created by the static
  56. * factory method LIB_TREE_MODEL_ADAPTER::Create().
  57. *
  58. * Quick summary of methods used to drive this class:
  59. *
  60. * - `SetFilter()` - set whether the view is restricted to power parts
  61. * - `ShowUnits()` - set whether units are displayed
  62. * - `SetPreselectNode()` - set a node to highlight when not searching
  63. * - `AddLibrary()` - populate the model with all aliases in a library
  64. * - `AddAliasList()` - populate the model with a specific list of aliases
  65. *
  66. * Quick summary of methods used by the View:
  67. *
  68. * - `UpdateSearchString()` - pass in the user's search text
  69. * - `AttachTo()` - pass in the wxDataViewCtrl
  70. * - `GetAliasFor()` - get the LIB_ALIAS* for a selected item
  71. * - `GetUnitFor()` - get the unit for a selected item
  72. * - `GetComponentsCount()` - count the aliases loaded
  73. *
  74. * Methods implemented as part of wxDataViewModel:
  75. *
  76. * - `HasContainerColumns()` - whether a parent item has more than one column
  77. * - `IsContainer()` - whether an item is a parent
  78. * - `GetParent()` - return the parent of an item, or invalid if root
  79. * - `GetChildren()` - get the children of an item
  80. * - `GetColumnCount()` - get the number of columns in the view
  81. * - `GetColumnType()` - get the data type shown in each column
  82. * - `GetValue()` - get the data shown in a cell
  83. * - `SetValue()` - edit the data in a cell (does nothing)
  84. * - `GetAttr()` - get any per-item formatting
  85. * - `Compare()` - compare two rows, for sorting
  86. * - `HasDefaultCompare()` - whether sorted by default
  87. */
  88. class APP_SETTINGS_BASE;
  89. class TOOL_INTERACTIVE;
  90. class EDA_BASE_FRAME;
  91. class LIB_TREE_MODEL_ADAPTER: public wxDataViewModel
  92. {
  93. public:
  94. /**
  95. * Destructor. Do NOT delete this class manually; it is reference-counted
  96. * by wxObject.
  97. */
  98. ~LIB_TREE_MODEL_ADAPTER();
  99. /**
  100. * This enum allows a selective filtering of symbols to list
  101. */
  102. enum SYM_FILTER_TYPE
  103. {
  104. SYM_FILTER_NONE, ///< no filtering
  105. SYM_FILTER_POWER, ///< list symbols flagged PWR
  106. };
  107. /**
  108. * This enum defines the order of the columns in the tree view
  109. */
  110. enum TREE_COLS
  111. {
  112. PART_COL = 0, ///< Part name column
  113. DESC_COL, ///< Part description column
  114. NUM_COLS ///< The number of tree columns
  115. };
  116. /**
  117. * Save the column widths to the config file. This requires the tree view to still be
  118. * valid.
  119. */
  120. void SaveColWidths();
  121. void SavePinnedItems();
  122. /**
  123. * Set the symbol filter type. Must be set before adding libraries
  124. *
  125. * @param aFilter if SYM_FILTER_POWER, only power parts are loaded
  126. */
  127. void SetFilter( SYM_FILTER_TYPE aFilter );
  128. /**
  129. * Return the active filter.
  130. */
  131. SYM_FILTER_TYPE GetFilter() const { return m_filter; }
  132. /**
  133. * Whether or not to show units. May be set at any time; updates at the next
  134. * UpdateSearchString()
  135. *
  136. * @param aShow if true, units are displayed
  137. */
  138. void ShowUnits( bool aShow );
  139. /**
  140. * Set the symbol name to be selected if there are no search results.
  141. * May be set at any time; updates at the next UpdateSearchString().
  142. *
  143. * @param aLibId symbol #LIB_ID to be selected
  144. * @param aUnit unit to be selected, if > 0 (0 selects the alias itself)
  145. */
  146. void SetPreselectNode( const LIB_ID& aLibId, int aUnit );
  147. /**
  148. * Add the given list of symbols by alias. To be called in the setup
  149. * phase.
  150. *
  151. * @param aNodeName the parent node the symbols will appear under
  152. * @param aDesc the description field of the parent node
  153. * @param aItemList list of symbols
  154. */
  155. void DoAddLibrary( const wxString& aNodeName, const wxString& aDesc,
  156. const std::vector<LIB_TREE_ITEM*>& aItemList, bool presorted );
  157. /**
  158. * Sort the tree and assign ranks after adding libraries.
  159. */
  160. void AssignIntrinsicRanks() { m_tree.AssignIntrinsicRanks(); }
  161. /**
  162. * Set the search string provided by the user.
  163. *
  164. * @param aSearch full, unprocessed search text
  165. * @param aState if true, we are keeping the state and so we shouldn't collapse the tree
  166. */
  167. void UpdateSearchString( const wxString& aSearch, bool aState );
  168. /**
  169. * Attach to a wxDataViewCtrl and initialize it. This will set up columns
  170. * and associate the model via the adapter.
  171. *
  172. * @param aDataViewCtrl the view symbol in the dialog
  173. */
  174. void AttachTo( wxDataViewCtrl* aDataViewCtrl );
  175. /**
  176. * A final-stage initialization to be called after the window hierarchy has been realized
  177. * and the window sizes set.
  178. */
  179. void FinishTreeInitialization();
  180. /**
  181. * Return the alias for the given item.
  182. *
  183. * @param aSelection item from the wxDataViewCtrl
  184. * (see wxDataViewCtrl::GetSelection())
  185. *
  186. * @return alias, or nullptr if none is selected
  187. */
  188. LIB_ID GetAliasFor( const wxDataViewItem& aSelection ) const;
  189. /**
  190. * Return the unit for the given item.
  191. *
  192. * @param aSelection item from the wxDataViewCtrl
  193. * (see wxDataViewCtrl::GetSelection())
  194. *
  195. * @return Unit, or zero if the alias itself is selected. Return valid is
  196. * invalid if GetAliasFor() returns nullptr.
  197. */
  198. int GetUnitFor( const wxDataViewItem& aSelection ) const;
  199. /**
  200. * Return node type for the given item.
  201. *
  202. * @param aSelection item from the wxDataViewCtrl
  203. * (see wxDataViewCtrl::GetSelection())
  204. *
  205. * @return Type of the selected node, might be INVALID.
  206. */
  207. LIB_TREE_NODE::TYPE GetTypeFor( const wxDataViewItem& aSelection ) const;
  208. LIB_TREE_NODE* GetTreeNodeFor( const wxDataViewItem& aSelection ) const;
  209. virtual wxString GenerateInfo( const LIB_ID& aLibId, int aUnit ) { return wxEmptyString; };
  210. /**
  211. * Return the number of symbols loaded in the tree.
  212. */
  213. int GetItemCount() const;
  214. /**
  215. * Return the number of libraries loaded in the tree.
  216. */
  217. virtual int GetLibrariesCount() const
  218. {
  219. return m_tree.m_Children.size();
  220. }
  221. /**
  222. * Returns tree item corresponding to part.
  223. *
  224. * @param aLibId specifies the part and library name to be searched for.
  225. * @return Tree data item representing the part. Might be invalid if nothings was found.
  226. */
  227. wxDataViewItem FindItem( const LIB_ID& aLibId );
  228. /**
  229. * Populate a list of all the children of an item
  230. *
  231. * @return number of children
  232. */
  233. unsigned int GetChildren( const wxDataViewItem& aItem,
  234. wxDataViewItemArray& aChildren ) const override;
  235. // Freezing/Thawing. Used when updating the table model so that we don't try and fetch
  236. // values during updating. Primarily a problem on OSX which doesn't pay attention to the
  237. // wxDataViewCtrl's freeze count when updating the keyWindow.
  238. void Freeze() { m_freeze++; }
  239. void Thaw() { m_freeze--; }
  240. bool IsFrozen() const { return m_freeze; }
  241. void RefreshTree();
  242. // Allows subclasses to nominate a context menu handler.
  243. virtual TOOL_INTERACTIVE* GetContextMenuTool() { return nullptr; }
  244. protected:
  245. /**
  246. * Convert #SYM_TREE_NODE -> wxDataViewItem.
  247. */
  248. static wxDataViewItem ToItem( const LIB_TREE_NODE* aNode );
  249. /**
  250. * Convert wxDataViewItem -> #SYM_TREE_NODE.
  251. */
  252. static LIB_TREE_NODE* ToNode( wxDataViewItem aItem );
  253. /**
  254. * Convert SYM_TREE_NODE's children to wxDataViewItemArray.
  255. */
  256. static unsigned int IntoArray( const LIB_TREE_NODE& aNode, wxDataViewItemArray& aChildren );
  257. /**
  258. * Create the adapter.
  259. *
  260. * @param aParent is the parent frame
  261. * @param aPinnedKey is the key to load the pinned libraries list from the project file
  262. */
  263. LIB_TREE_MODEL_ADAPTER( EDA_BASE_FRAME* aParent, const wxString& aPinnedKey );
  264. LIB_TREE_NODE_LIB& DoAddLibraryNode( const wxString& aNodeName, const wxString& aDesc );
  265. /**
  266. * Check whether a container has columns too
  267. */
  268. bool HasContainerColumns( const wxDataViewItem& aItem ) const override;
  269. /**
  270. * Check whether an item can have children.
  271. */
  272. bool IsContainer( const wxDataViewItem& aItem ) const override;
  273. /**
  274. * Get the parent of an item.
  275. *
  276. * @return parent of aItem, or an invalid wxDataViewItem if parent is root
  277. */
  278. wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override;
  279. unsigned int GetColumnCount() const override { return NUM_COLS; }
  280. /**
  281. * Return the type of data stored in the column as indicated by wxVariant::GetType()
  282. */
  283. wxString GetColumnType( unsigned int aCol ) const override { return "string"; }
  284. /**
  285. * Get the value of an item.
  286. *
  287. * @param aVariant wxVariant to receive the data
  288. * @param aItem item whose data will be placed into aVariant
  289. * @param aCol column number of the data
  290. */
  291. void GetValue( wxVariant& aVariant,
  292. const wxDataViewItem& aItem,
  293. unsigned int aCol ) const override;
  294. /**
  295. * Set the value of an item. Does nothing - this model doesn't support
  296. * editing.
  297. */
  298. bool SetValue( const wxVariant& aVariant,
  299. const wxDataViewItem& aItem,
  300. unsigned int aCol ) override { return false; }
  301. /**
  302. * Get any formatting for an item.
  303. *
  304. * @param aItem item to get formatting for
  305. * @param aCol column number of interest
  306. * @param aAttr receiver for attributes
  307. * @return true if the item has non-default attributes
  308. */
  309. bool GetAttr( const wxDataViewItem& aItem,
  310. unsigned int aCol,
  311. wxDataViewItemAttr& aAttr ) const override;
  312. /**
  313. * @return a unicode string to mark a node name like
  314. * a pinned library name
  315. * This is not an ASCII7 char, but a unicode char
  316. */
  317. const wxString GetPinningSymbol() const
  318. {
  319. return wxString::FromUTF8( "" );
  320. }
  321. private:
  322. /**
  323. * Find any results worth highlighting and expand them, according to given criteria
  324. * The highest-scoring node is written to aHighScore
  325. */
  326. void FindAndExpand( LIB_TREE_NODE& aNode, std::function<bool( const LIB_TREE_NODE* )> aFunc,
  327. LIB_TREE_NODE** aHighScore );
  328. /**
  329. * Find and expand successful search results. Return the best match (if any).
  330. */
  331. LIB_TREE_NODE* ShowResults();
  332. /**
  333. * Find and expand preselected node. Return the best match (if any).
  334. */
  335. LIB_TREE_NODE* ShowPreselect();
  336. /**
  337. * Find and expand a library if there is only one. Return the best match (if any).
  338. */
  339. LIB_TREE_NODE* ShowSingleLibrary();
  340. protected:
  341. LIB_TREE_NODE_ROOT m_tree;
  342. private:
  343. EDA_BASE_FRAME* m_parent;
  344. SYM_FILTER_TYPE m_filter;
  345. bool m_show_units;
  346. LIB_ID m_preselect_lib_id;
  347. int m_preselect_unit;
  348. int m_freeze;
  349. wxDataViewColumn* m_col_part;
  350. wxDataViewColumn* m_col_desc;
  351. wxDataViewCtrl* m_widget;
  352. int m_colWidths[NUM_COLS];
  353. wxArrayString m_pinnedLibs;
  354. wxString m_pinnedKey;
  355. };
  356. #endif // LIB_TREE_MODEL_ADAPTER_H