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.
		
		
		
		
		
			
		
			
				
					
					
						
							293 lines
						
					
					
						
							10 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							293 lines
						
					
					
						
							10 KiB
						
					
					
				
								/*
							 | 
						|
								 * This program source code file is part of KiCad, a free EDA CAD application.
							 | 
						|
								 *
							 | 
						|
								 * Copyright (C) 2023 <author>
							 | 
						|
								 * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
							 | 
						|
								 *
							 | 
						|
								 * This program is free software: you can redistribute it and/or modify it
							 | 
						|
								 * under the terms of the GNU General Public License as published by the
							 | 
						|
								 * Free Software Foundation, either version 3 of the License, or (at your
							 | 
						|
								 * option) any later version.
							 | 
						|
								 *
							 | 
						|
								 * This program is distributed in the hope that it will be useful, but
							 | 
						|
								 * WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						|
								 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
							 | 
						|
								 * General Public License for more details.
							 | 
						|
								 *
							 | 
						|
								 * You should have received a copy of the GNU General Public License along
							 | 
						|
								 * with this program.  If not, see <http://www.gnu.org/licenses/>.
							 | 
						|
								 */
							 | 
						|
								#include <sch_reference_list.h>
							 | 
						|
								#include <wx/grid.h>
							 | 
						|
								
							 | 
						|
								// The field name in the data model (translated)
							 | 
						|
								#define DISPLAY_NAME_COLUMN   0
							 | 
						|
								
							 | 
						|
								// The field name's label for exporting (CSV, etc.)
							 | 
						|
								#define LABEL_COLUMN          1
							 | 
						|
								#define SHOW_FIELD_COLUMN     2
							 | 
						|
								#define GROUP_BY_COLUMN       3
							 | 
						|
								
							 | 
						|
								// The internal field name (untranslated)
							 | 
						|
								#define FIELD_NAME_COLUMN     4
							 | 
						|
								
							 | 
						|
								struct BOM_FIELD;
							 | 
						|
								struct BOM_PRESET;
							 | 
						|
								struct BOM_FMT_PRESET;
							 | 
						|
								
							 | 
						|
								enum GROUP_TYPE
							 | 
						|
								{
							 | 
						|
								    GROUP_SINGLETON,
							 | 
						|
								    GROUP_COLLAPSED,
							 | 
						|
								    GROUP_COLLAPSED_DURING_SORT,
							 | 
						|
								    GROUP_EXPANDED,
							 | 
						|
								    CHILD_ITEM
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								struct DATA_MODEL_ROW
							 | 
						|
								{
							 | 
						|
								    DATA_MODEL_ROW( const SCH_REFERENCE& aFirstReference, GROUP_TYPE aType )
							 | 
						|
								    {
							 | 
						|
								        m_ItemNumber = 0;
							 | 
						|
								        m_Refs.push_back( aFirstReference );
							 | 
						|
								        m_Flag = aType;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    int                        m_ItemNumber;
							 | 
						|
								    GROUP_TYPE                 m_Flag;
							 | 
						|
								    std::vector<SCH_REFERENCE> m_Refs;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								struct DATA_MODEL_COL
							 | 
						|
								{
							 | 
						|
								    wxString m_fieldName;
							 | 
						|
								    wxString m_label;
							 | 
						|
								    bool     m_userAdded;
							 | 
						|
								    bool     m_show;
							 | 
						|
								    bool     m_group;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase
							 | 
						|
								{
							 | 
						|
								public:
							 | 
						|
								    enum SCOPE : int
							 | 
						|
								    {
							 | 
						|
								        SCOPE_ALL = 0,
							 | 
						|
								        SCOPE_SHEET = 1,
							 | 
						|
								        SCOPE_SHEET_RECURSIVE = 2
							 | 
						|
								    };
							 | 
						|
								
							 | 
						|
								    FIELDS_EDITOR_GRID_DATA_MODEL( SCH_REFERENCE_LIST& aSymbolsList ) :
							 | 
						|
								            m_symbolsList( aSymbolsList ), m_edited( false ), m_sortColumn( 0 ),
							 | 
						|
								            m_sortAscending( false ), m_scope( SCOPE_ALL ), m_groupingEnabled( false ),
							 | 
						|
								            m_excludeDNP( false ), m_includeExcluded( false ), m_rebuildsEnabled( true )
							 | 
						|
								    {
							 | 
						|
								        m_symbolsList.SplitReferences();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    static const wxString QUANTITY_VARIABLE;
							 | 
						|
								    static const wxString ITEM_NUMBER_VARIABLE;
							 | 
						|
								
							 | 
						|
								    void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser );
							 | 
						|
								    void RemoveColumn( int aCol );
							 | 
						|
								    void RenameColumn( int aCol, const wxString& newName );
							 | 
						|
								
							 | 
						|
								    void MoveColumn( int aCol, int aNewPos )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
							 | 
						|
								        std::swap( m_cols[aCol], m_cols[aNewPos] );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    int GetNumberRows() override { return (int) m_rows.size(); }
							 | 
						|
								    int GetNumberCols() override { return (int) m_cols.size(); }
							 | 
						|
								
							 | 
						|
								    void SetColLabelValue( int aCol, const wxString& aLabel ) override
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
							 | 
						|
								        m_cols[aCol].m_label = aLabel;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    wxString GetColLabelValue( int aCol ) override
							 | 
						|
								    {
							 | 
						|
								        wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
							 | 
						|
								        return m_cols[aCol].m_label;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    wxString GetColFieldName( int aCol )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
							 | 
						|
								        return m_cols[aCol].m_fieldName;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    int      GetFieldNameCol( wxString aFieldName );
							 | 
						|
								
							 | 
						|
								    const std::vector<BOM_FIELD> GetFieldsOrdered();
							 | 
						|
								    void                         SetFieldsOrder( const std::vector<wxString>& aNewOrder );
							 | 
						|
								
							 | 
						|
								    bool IsEmptyCell( int aRow, int aCol ) override
							 | 
						|
								    {
							 | 
						|
								        return false; // don't allow adjacent cell overflow, even if we are actually empty
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    wxString GetValue( int aRow, int aCol ) override;
							 | 
						|
								    wxString GetValue( const DATA_MODEL_ROW& group, int aCol,
							 | 
						|
								                       const wxString& refDelimiter = wxT( ", " ),
							 | 
						|
								                       const wxString& refRangDelimiter = wxT( "-" ),
							 | 
						|
								                       bool resolveVars = false );
							 | 
						|
								
							 | 
						|
								    wxString GetExportValue( int aRow, int aCol, const wxString& refDelimiter,
							 | 
						|
								                             const wxString& refRangeDelimiter )
							 | 
						|
								    {
							 | 
						|
								        return GetValue( m_rows[aRow], aCol, refDelimiter, refRangeDelimiter, true );
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    void     SetValue( int aRow, int aCol, const wxString& aValue ) override;
							 | 
						|
								
							 | 
						|
								    GROUP_TYPE GetRowFlags( int aRow ) { return m_rows[aRow].m_Flag; }
							 | 
						|
								
							 | 
						|
								    std::vector<SCH_REFERENCE> GetRowReferences( int aRow ) const
							 | 
						|
								    {
							 | 
						|
								        wxCHECK( aRow >= 0 && aRow < (int) m_rows.size(), std::vector<SCH_REFERENCE>() );
							 | 
						|
								        return m_rows[aRow].m_Refs;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    bool ColIsReference( int aCol );
							 | 
						|
								    bool ColIsValue( int aCol );
							 | 
						|
								    bool ColIsQuantity( int aCol );
							 | 
						|
								    bool ColIsItemNumber( int aCol );
							 | 
						|
								    bool ColIsAttribute( int aCol );
							 | 
						|
								
							 | 
						|
								    void SetSorting( int aCol, bool ascending )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
							 | 
						|
								        m_sortColumn = aCol;
							 | 
						|
								        m_sortAscending = ascending;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    int  GetSortCol() { return m_sortColumn; }
							 | 
						|
								    bool GetSortAsc() { return m_sortAscending; }
							 | 
						|
								
							 | 
						|
								    // These are used to disable the RebuildRows functionality while we're generating
							 | 
						|
								    // lots of events in the UI, e.g. applying a BOM preset, that would thrash the grid.
							 | 
						|
								    void EnableRebuilds();
							 | 
						|
								    void DisableRebuilds();
							 | 
						|
								    void RebuildRows();
							 | 
						|
								
							 | 
						|
								    void ExpandRow( int aRow );
							 | 
						|
								    void CollapseRow( int aRow );
							 | 
						|
								    void ExpandCollapseRow( int aRow );
							 | 
						|
								    void CollapseForSort();
							 | 
						|
								    void ExpandAfterSort();
							 | 
						|
								
							 | 
						|
								    void ApplyData( std::function<void( SCH_SYMBOL&, SCH_SHEET_PATH& )> symbolChangeHandler );
							 | 
						|
								
							 | 
						|
								    bool IsEdited() { return m_edited; }
							 | 
						|
								
							 | 
						|
								    int GetDataWidth( int aCol );
							 | 
						|
								
							 | 
						|
								    void SetFilter( const wxString& aFilter ) { m_filter = aFilter; }
							 | 
						|
								    const wxString& GetFilter() { return m_filter; }
							 | 
						|
								
							 | 
						|
								    void  SetScope( SCOPE aScope ) { m_scope = aScope; }
							 | 
						|
								    SCOPE GetScope() { return m_scope; }
							 | 
						|
								
							 | 
						|
								    void                  SetPath( const SCH_SHEET_PATH& aPath ) { m_path = aPath; }
							 | 
						|
								    const SCH_SHEET_PATH& GetPath() { return m_path; }
							 | 
						|
								
							 | 
						|
								    void SetGroupingEnabled( bool group ) { m_groupingEnabled = group; }
							 | 
						|
								    bool GetGroupingEnabled() { return m_groupingEnabled; }
							 | 
						|
								
							 | 
						|
								    /* These contradictorily named functions force including symbols that
							 | 
						|
								     * have the Exclude from BOM check box ticked. This is needed so we can view
							 | 
						|
								     * these parts in the symbol fields table dialog, while also excluding from the
							 | 
						|
								     * BOM export */
							 | 
						|
								    void SetIncludeExcludedFromBOM( bool include ) { m_includeExcluded = include; }
							 | 
						|
								    bool GetIncludeExcludedFromBOM() { return m_includeExcluded; }
							 | 
						|
								
							 | 
						|
								    void SetExcludeDNP( bool exclude ) { m_excludeDNP = exclude; }
							 | 
						|
								    bool GetExcludeDNP() { return m_excludeDNP; }
							 | 
						|
								
							 | 
						|
								    void SetGroupColumn( int aCol, bool group )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
							 | 
						|
								        m_cols[aCol].m_group = group;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    bool GetGroupColumn( int aCol )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
							 | 
						|
								        return m_cols[aCol].m_group;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    void SetShowColumn( int aCol, bool show )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
							 | 
						|
								        m_cols[aCol].m_show = show;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    bool GetShowColumn( int aCol )
							 | 
						|
								    {
							 | 
						|
								        wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
							 | 
						|
								        return m_cols[aCol].m_show;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    void     ApplyBomPreset( const BOM_PRESET& preset );
							 | 
						|
								    BOM_PRESET GetBomSettings();
							 | 
						|
								    wxString Export( const BOM_FMT_PRESET& settings );
							 | 
						|
								
							 | 
						|
								    void AddReferences( const SCH_REFERENCE_LIST& aRefs );
							 | 
						|
								    void RemoveReferences( const SCH_REFERENCE_LIST& aRefs );
							 | 
						|
								    void RemoveSymbol( const SCH_SYMBOL& aSymbol );
							 | 
						|
								    void UpdateReferences( const SCH_REFERENCE_LIST& aRefs );
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								private:
							 | 
						|
								    static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup,
							 | 
						|
								                     FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending );
							 | 
						|
								    bool        unitMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef );
							 | 
						|
								    bool        groupMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef );
							 | 
						|
								
							 | 
						|
								    // Helper functions to deal with translating wxGrid values to and from
							 | 
						|
								    // named field values like ${DNP}
							 | 
						|
								    bool     isAttribute( const wxString& aFieldName );
							 | 
						|
								    wxString getAttributeValue( const SCH_SYMBOL&, const wxString& aAttributeName );
							 | 
						|
								    void     setAttributeValue( SCH_SYMBOL& aSymbol, const wxString& aAttributeName,
							 | 
						|
								                                const wxString& aValue );
							 | 
						|
								
							 | 
						|
								    /* Helper function to get the resolved field value.
							 | 
						|
								     * Handles symbols that are missing fields that would have a variable
							 | 
						|
								     * in their value because their name is the same as a variable.
							 | 
						|
								     * Example: BOM template provides ${DNP} as a field, but they symbol doesn't have the field. */
							 | 
						|
								    wxString getFieldShownText( const SCH_REFERENCE& aRef, const wxString& aFieldName );
							 | 
						|
								
							 | 
						|
								    void Sort();
							 | 
						|
								
							 | 
						|
								    SCH_REFERENCE_LIST getSymbolReferences( SCH_SYMBOL* aSymbol );
							 | 
						|
								    void               storeReferenceFields( SCH_REFERENCE& aRef );
							 | 
						|
								    void updateDataStoreSymbolField( const SCH_SYMBOL& aSymbol, const wxString& aFieldName );
							 | 
						|
								
							 | 
						|
								protected:
							 | 
						|
								    SCH_REFERENCE_LIST m_symbolsList;
							 | 
						|
								    bool               m_edited;
							 | 
						|
								    int                m_sortColumn;
							 | 
						|
								    bool               m_sortAscending;
							 | 
						|
								    wxString           m_filter;
							 | 
						|
								    enum SCOPE         m_scope;
							 | 
						|
								    SCH_SHEET_PATH     m_path;
							 | 
						|
								    bool               m_groupingEnabled;
							 | 
						|
								    bool               m_excludeDNP;
							 | 
						|
								    bool               m_includeExcluded;
							 | 
						|
								    bool               m_rebuildsEnabled;
							 | 
						|
								
							 | 
						|
								    std::vector<DATA_MODEL_COL> m_cols;
							 | 
						|
								    std::vector<DATA_MODEL_ROW> m_rows;
							 | 
						|
								
							 | 
						|
								    // Data store
							 | 
						|
								    // The data model is fundamentally m_componentRefs X m_fieldNames.
							 | 
						|
								    // A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue
							 | 
						|
								    std::map<KIID, std::map<wxString, wxString>> m_dataStore;
							 | 
						|
								};
							 |