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.

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