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.

440 lines
15 KiB

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