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.

301 lines
10 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2023 <author>
  5. * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software: you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation, either version 3 of the License, or (at your
  10. * option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <sch_reference_list.h>
  21. #include <wx/grid.h>
  22. // The field name in the data model (translated)
  23. #define DISPLAY_NAME_COLUMN 0
  24. // The field name's label for exporting (CSV, etc.)
  25. #define LABEL_COLUMN 1
  26. #define SHOW_FIELD_COLUMN 2
  27. #define GROUP_BY_COLUMN 3
  28. // The internal field name (untranslated)
  29. #define FIELD_NAME_COLUMN 4
  30. struct BOM_FIELD;
  31. struct BOM_PRESET;
  32. struct BOM_FMT_PRESET;
  33. enum GROUP_TYPE
  34. {
  35. GROUP_SINGLETON,
  36. GROUP_COLLAPSED,
  37. GROUP_COLLAPSED_DURING_SORT,
  38. GROUP_EXPANDED,
  39. CHILD_ITEM
  40. };
  41. struct DATA_MODEL_ROW
  42. {
  43. DATA_MODEL_ROW( const SCH_REFERENCE& aFirstReference, GROUP_TYPE aType )
  44. {
  45. m_ItemNumber = 0;
  46. m_Refs.push_back( aFirstReference );
  47. m_Flag = aType;
  48. }
  49. int m_ItemNumber;
  50. GROUP_TYPE m_Flag;
  51. std::vector<SCH_REFERENCE> m_Refs;
  52. };
  53. struct DATA_MODEL_COL
  54. {
  55. wxString m_fieldName;
  56. wxString m_label;
  57. bool m_userAdded;
  58. bool m_show;
  59. bool m_group;
  60. };
  61. class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase
  62. {
  63. public:
  64. enum SCOPE : int
  65. {
  66. SCOPE_ALL = 0,
  67. SCOPE_SHEET = 1,
  68. SCOPE_SHEET_RECURSIVE = 2
  69. };
  70. FIELDS_EDITOR_GRID_DATA_MODEL( SCH_REFERENCE_LIST& aSymbolsList ) :
  71. m_symbolsList( aSymbolsList ), m_edited( false ), m_sortColumn( 0 ),
  72. m_sortAscending( false ), m_scope( SCOPE_ALL ), m_groupingEnabled( false ),
  73. m_excludeDNP( false ), m_includeExcluded( false ), m_rebuildsEnabled( true )
  74. {
  75. m_symbolsList.SplitReferences();
  76. }
  77. static const wxString QUANTITY_VARIABLE;
  78. static const wxString ITEM_NUMBER_VARIABLE;
  79. void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser );
  80. void RemoveColumn( int aCol );
  81. void RenameColumn( int aCol, const wxString& newName );
  82. void MoveColumn( int aCol, int aNewPos )
  83. {
  84. wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
  85. if( aCol == aNewPos )
  86. return;
  87. else if( aCol < aNewPos )
  88. std::rotate( std::begin( m_cols ) + aCol, std::begin( m_cols ) + aCol + 1,
  89. std::begin( m_cols ) + aNewPos + 1 );
  90. else
  91. std::rotate( std::begin( m_cols ) + aNewPos, std::begin( m_cols ) + aCol,
  92. std::begin( m_cols ) + aCol + 1 );
  93. }
  94. int GetNumberRows() override { return (int) m_rows.size(); }
  95. int GetNumberCols() override { return (int) m_cols.size(); }
  96. void SetColLabelValue( int aCol, const wxString& aLabel ) override
  97. {
  98. wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
  99. m_cols[aCol].m_label = aLabel;
  100. }
  101. wxString GetColLabelValue( int aCol ) override
  102. {
  103. wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
  104. return m_cols[aCol].m_label;
  105. }
  106. wxString GetColFieldName( int aCol )
  107. {
  108. wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
  109. return m_cols[aCol].m_fieldName;
  110. }
  111. int GetFieldNameCol( wxString aFieldName );
  112. const std::vector<BOM_FIELD> GetFieldsOrdered();
  113. void SetFieldsOrder( const std::vector<wxString>& aNewOrder );
  114. bool IsEmptyCell( int aRow, int aCol ) override
  115. {
  116. return false; // don't allow adjacent cell overflow, even if we are actually empty
  117. }
  118. wxString GetValue( int aRow, int aCol ) override;
  119. wxString GetValue( const DATA_MODEL_ROW& group, int aCol,
  120. const wxString& refDelimiter = wxT( ", " ),
  121. const wxString& refRangDelimiter = wxT( "-" ),
  122. bool resolveVars = false );
  123. wxString GetExportValue( int aRow, int aCol, const wxString& refDelimiter,
  124. const wxString& refRangeDelimiter )
  125. {
  126. return GetValue( m_rows[aRow], aCol, refDelimiter, refRangeDelimiter, true );
  127. }
  128. void SetValue( int aRow, int aCol, const wxString& aValue ) override;
  129. GROUP_TYPE GetRowFlags( int aRow ) { return m_rows[aRow].m_Flag; }
  130. std::vector<SCH_REFERENCE> GetRowReferences( int aRow ) const
  131. {
  132. wxCHECK( aRow >= 0 && aRow < (int) m_rows.size(), std::vector<SCH_REFERENCE>() );
  133. return m_rows[aRow].m_Refs;
  134. }
  135. bool ColIsReference( int aCol );
  136. bool ColIsValue( int aCol );
  137. bool ColIsQuantity( int aCol );
  138. bool ColIsItemNumber( int aCol );
  139. bool ColIsAttribute( int aCol );
  140. void SetSorting( int aCol, bool ascending )
  141. {
  142. wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
  143. m_sortColumn = aCol;
  144. m_sortAscending = ascending;
  145. }
  146. int GetSortCol() { return m_sortColumn; }
  147. bool GetSortAsc() { return m_sortAscending; }
  148. // These are used to disable the RebuildRows functionality while we're generating
  149. // lots of events in the UI, e.g. applying a BOM preset, that would thrash the grid.
  150. void EnableRebuilds();
  151. void DisableRebuilds();
  152. void RebuildRows();
  153. void ExpandRow( int aRow );
  154. void CollapseRow( int aRow );
  155. void ExpandCollapseRow( int aRow );
  156. void CollapseForSort();
  157. void ExpandAfterSort();
  158. void ApplyData( std::function<void( SCH_SYMBOL&, SCH_SHEET_PATH& )> symbolChangeHandler );
  159. bool IsEdited() { return m_edited; }
  160. int GetDataWidth( int aCol );
  161. void SetFilter( const wxString& aFilter ) { m_filter = aFilter; }
  162. const wxString& GetFilter() { return m_filter; }
  163. void SetScope( SCOPE aScope ) { m_scope = aScope; }
  164. SCOPE GetScope() { return m_scope; }
  165. void SetPath( const SCH_SHEET_PATH& aPath ) { m_path = aPath; }
  166. const SCH_SHEET_PATH& GetPath() { return m_path; }
  167. void SetGroupingEnabled( bool group ) { m_groupingEnabled = group; }
  168. bool GetGroupingEnabled() { return m_groupingEnabled; }
  169. /* These contradictorily named functions force including symbols that
  170. * have the Exclude from BOM check box ticked. This is needed so we can view
  171. * these parts in the symbol fields table dialog, while also excluding from the
  172. * BOM export */
  173. void SetIncludeExcludedFromBOM( bool include ) { m_includeExcluded = include; }
  174. bool GetIncludeExcludedFromBOM() { return m_includeExcluded; }
  175. void SetExcludeDNP( bool exclude ) { m_excludeDNP = exclude; }
  176. bool GetExcludeDNP() { return m_excludeDNP; }
  177. void SetGroupColumn( int aCol, bool group )
  178. {
  179. wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
  180. m_cols[aCol].m_group = group;
  181. }
  182. bool GetGroupColumn( int aCol )
  183. {
  184. wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
  185. return m_cols[aCol].m_group;
  186. }
  187. void SetShowColumn( int aCol, bool show )
  188. {
  189. wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
  190. m_cols[aCol].m_show = show;
  191. }
  192. bool GetShowColumn( int aCol )
  193. {
  194. wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
  195. return m_cols[aCol].m_show;
  196. }
  197. void ApplyBomPreset( const BOM_PRESET& preset );
  198. BOM_PRESET GetBomSettings();
  199. wxString Export( const BOM_FMT_PRESET& settings );
  200. void AddReferences( const SCH_REFERENCE_LIST& aRefs );
  201. void RemoveReferences( const SCH_REFERENCE_LIST& aRefs );
  202. void RemoveSymbol( const SCH_SYMBOL& aSymbol );
  203. void UpdateReferences( const SCH_REFERENCE_LIST& aRefs );
  204. private:
  205. static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup,
  206. FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending );
  207. bool unitMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef );
  208. bool groupMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef );
  209. // Helper functions to deal with translating wxGrid values to and from
  210. // named field values like ${DNP}
  211. bool isAttribute( const wxString& aFieldName );
  212. wxString getAttributeValue( const SCH_SYMBOL&, const wxString& aAttributeName );
  213. void setAttributeValue( SCH_SYMBOL& aSymbol, const wxString& aAttributeName,
  214. const wxString& aValue );
  215. /* Helper function to get the resolved field value.
  216. * Handles symbols that are missing fields that would have a variable
  217. * in their value because their name is the same as a variable.
  218. * Example: BOM template provides ${DNP} as a field, but they symbol doesn't have the field. */
  219. wxString getFieldShownText( const SCH_REFERENCE& aRef, const wxString& aFieldName );
  220. void Sort();
  221. SCH_REFERENCE_LIST getSymbolReferences( SCH_SYMBOL* aSymbol );
  222. void storeReferenceFields( SCH_REFERENCE& aRef );
  223. void updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol, const wxString& aFieldName );
  224. protected:
  225. SCH_REFERENCE_LIST m_symbolsList;
  226. bool m_edited;
  227. int m_sortColumn;
  228. bool m_sortAscending;
  229. wxString m_filter;
  230. enum SCOPE m_scope;
  231. SCH_SHEET_PATH m_path;
  232. bool m_groupingEnabled;
  233. bool m_excludeDNP;
  234. bool m_includeExcluded;
  235. bool m_rebuildsEnabled;
  236. std::vector<DATA_MODEL_COL> m_cols;
  237. std::vector<DATA_MODEL_ROW> m_rows;
  238. // Data store
  239. // The data model is fundamentally m_componentRefs X m_fieldNames.
  240. // A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue
  241. std::map<KIID, std::map<wxString, wxString>> m_dataStore;
  242. };