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.

333 lines
11 KiB

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