diff --git a/bitmaps_png/CMakeLists.txt b/bitmaps_png/CMakeLists.txt index b8cdfef23c..1d5cd2c2cd 100644 --- a/bitmaps_png/CMakeLists.txt +++ b/bitmaps_png/CMakeLists.txt @@ -98,6 +98,7 @@ set( BMAPS_SMALL pintype_opencoll pintype_openemit pintype_noconnect + refresh tree_nosel tree_sel ) diff --git a/bitmaps_png/cpp_16/refresh.cpp b/bitmaps_png/cpp_16/refresh.cpp new file mode 100644 index 0000000000..f38b5b1162 --- /dev/null +++ b/bitmaps_png/cpp_16/refresh.cpp @@ -0,0 +1,39 @@ + +/* Do not modify this file, it was automatically generated by the + * PNG2cpp CMake script, using a *.png file as input. + */ + +#include + +static const unsigned char png[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xff, + 0x61, 0x00, 0x00, 0x00, 0x04, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08, 0x08, 0x7c, 0x08, 0x64, + 0x88, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0e, 0xc4, 0x00, 0x00, 0x0e, + 0xc4, 0x01, 0x95, 0x2b, 0x0e, 0x1b, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, + 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, + 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x00, 0x00, 0x01, 0x14, 0x49, + 0x44, 0x41, 0x54, 0x38, 0x8d, 0x9d, 0xd3, 0xbd, 0x4a, 0x43, 0x41, 0x10, 0x05, 0xe0, 0xcf, 0x44, + 0x0d, 0x69, 0x6d, 0x04, 0x41, 0x8c, 0x60, 0xe7, 0x0f, 0xd8, 0x2a, 0xa2, 0x60, 0xa1, 0x4d, 0xf2, + 0x22, 0x8a, 0xb6, 0x62, 0x2f, 0x82, 0xb1, 0xf0, 0x25, 0x2c, 0x05, 0x15, 0x2c, 0x54, 0x62, 0x61, + 0x19, 0xc4, 0xc2, 0xbc, 0x80, 0xad, 0x0f, 0x10, 0x95, 0x88, 0x3f, 0xc5, 0xdd, 0xe8, 0x66, 0x89, + 0x92, 0x78, 0x60, 0x97, 0xbb, 0x73, 0xee, 0xcc, 0xd9, 0xe5, 0xcc, 0xf0, 0x3b, 0x06, 0x31, 0x89, + 0x12, 0xf2, 0x51, 0x7c, 0x17, 0xc5, 0x3f, 0xf2, 0x2c, 0xe1, 0x1c, 0x4d, 0x7c, 0x86, 0xd5, 0xc4, + 0x09, 0xf6, 0xc3, 0xb9, 0x14, 0xab, 0xb4, 0x91, 0xc7, 0x21, 0xb6, 0xf1, 0x8e, 0x1a, 0x1e, 0x90, + 0xc3, 0x2c, 0x2a, 0xd1, 0xff, 0xa3, 0x78, 0x4c, 0x95, 0x8f, 0x42, 0xf5, 0x9b, 0x58, 0x21, 0xa0, + 0x8c, 0x56, 0x74, 0xa3, 0x4a, 0x9a, 0xbc, 0x1c, 0x88, 0x1a, 0x86, 0x12, 0x6e, 0x06, 0x0d, 0xdc, + 0xa1, 0x8e, 0x6b, 0xac, 0xa7, 0x05, 0x2e, 0xf0, 0x81, 0xe9, 0x94, 0xe8, 0x05, 0xc3, 0x78, 0xc5, + 0xe5, 0x7f, 0x92, 0x73, 0x18, 0x47, 0x01, 0xf7, 0x7d, 0xe4, 0xcd, 0x63, 0x13, 0x23, 0xc2, 0xb6, + 0x11, 0x82, 0xbd, 0xe2, 0x40, 0x62, 0x67, 0xbf, 0xb8, 0xc2, 0x8b, 0xce, 0x36, 0xe8, 0x19, 0x53, + 0x78, 0xc3, 0x69, 0x4a, 0xac, 0xc9, 0x2c, 0xaa, 0xcb, 0x2c, 0x6b, 0xc8, 0x2c, 0x8c, 0x51, 0xc0, + 0xad, 0xcc, 0xb1, 0xc5, 0xb4, 0x40, 0xd9, 0x4f, 0xa3, 0xb4, 0xc2, 0x39, 0x55, 0xbe, 0x0d, 0x7c, + 0xb5, 0x1d, 0x8c, 0xdf, 0xf0, 0x14, 0x7d, 0x0f, 0x60, 0x0b, 0x2b, 0x41, 0x6d, 0x0e, 0xab, 0x32, + 0xd7, 0xaa, 0xd8, 0xe9, 0xf6, 0xb6, 0x89, 0x50, 0x7d, 0x0f, 0xc7, 0x3a, 0x87, 0xe9, 0x19, 0x67, + 0x58, 0xe8, 0x96, 0xd8, 0x46, 0x51, 0x36, 0xaa, 0xf1, 0x2d, 0xc6, 0x64, 0x23, 0x9d, 0xb6, 0xf7, + 0x37, 0xbe, 0x00, 0x48, 0xf6, 0x3b, 0x32, 0x64, 0x0d, 0x89, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x49, + 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, +}; + +const BITMAP_OPAQUE refresh_xpm[1] = {{ png, sizeof( png ), "refresh_xpm" }}; + +//EOF diff --git a/bitmaps_png/sources/refresh.svg b/bitmaps_png/sources/refresh.svg new file mode 100644 index 0000000000..00b1ad00ed --- /dev/null +++ b/bitmaps_png/sources/refresh.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/common/string.cpp b/common/string.cpp index d0375c55af..13b1d46cb0 100644 --- a/common/string.cpp +++ b/common/string.cpp @@ -362,56 +362,141 @@ bool WildCompareString( const wxString& pattern, const wxString& string_to_tst, } -int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord ) +bool ApplyModifier( double& value, const wxString& aString ) { - // The different sections of the first string + static const wxString modifiers( wxT( "pnumkKM" ) ); + + if( !aString.length() ) + return false; + + wxChar modifier; + wxString units; + + if( modifiers.Find( aString[ 0 ] ) >= 0 ) + { + modifier = aString[ 0 ]; + units = aString.Mid( 1 ).Trim(); + } + else + { + modifier = ' '; + units = aString.Mid( 0 ).Trim(); + } + + if( units.length() + && !units.CmpNoCase( wxT( "F" ) ) + && !units.CmpNoCase( wxT( "hz" ) ) + && !units.CmpNoCase( wxT( "W" ) ) + && !units.CmpNoCase( wxT( "V" ) ) + && !units.CmpNoCase( wxT( "H" ) ) ) + return false; + + if( modifier == 'p' ) + value *= 1.0e-12; + if( modifier == 'n' ) + value *= 1.0e-9; + else if( modifier == 'u' ) + value *= 1.0e-6; + else if( modifier == 'm' ) + value *= 1.0e-3; + else if( modifier == 'k' || modifier == 'K' ) + value *= 1.0e3; + else if( modifier == 'M' ) + value *= 1.0e6; + else if( modifier == 'G' ) + value *= 1.0e9; + + return true; +} + + +// Should handle: +// a) Purely numerical e.g. '22' +// b) Numerical with included units e.g. '15uF' +// c) Numerical with included prefix but no units e.g. '20n' +// d) Numerical with prefix inside number e.g. '4K7' +// e) Other, e.g. 'MAX232' +// +// TODO: case (d) unimplemented !!! +// +int ValueStringCompare( const wxString& strFWord, const wxString& strSWord ) +{ + // The different sections of the two strings wxString strFWordBeg, strFWordMid, strFWordEnd; - - // The different sections of the second string wxString strSWordBeg, strSWordMid, strSWordEnd; - int isEqual = 0; // The numerical results of a string compare - int iReturn = 0; // The variable that is being returned - - long lFirstDigit = 0; // The converted middle section of the first string - long lSecondDigit = 0; // The converted middle section of the second string - // Split the two strings into separate parts SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd ); SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd ); // Compare the Beginning section of the strings - isEqual = strFWordBeg.CmpNoCase( strSWordBeg ); + int isEqual = strFWordBeg.CmpNoCase( strSWordBeg ); if( isEqual > 0 ) - iReturn = 1; + return 1; else if( isEqual < 0 ) - iReturn = -1; + return -1; else { // If the first sections are equal compare their digits + double lFirstNumber = 0; + double lSecondNumber = 0; + bool endingIsModifier = false; + + strFWordMid.ToDouble( &lFirstNumber ); + strSWordMid.ToDouble( &lSecondNumber ); + + endingIsModifier |= ApplyModifier( lFirstNumber, strFWordEnd ); + endingIsModifier |= ApplyModifier( lSecondNumber, strSWordEnd ); + + if( lFirstNumber > lSecondNumber ) + return 1; + else if( lFirstNumber < lSecondNumber ) + return -1; + // If the first two sections are equal and the endings are modifiers then compare them + else if( !endingIsModifier ) + return strFWordEnd.CmpNoCase( strSWordEnd ); + // Ran out of things to compare; they must match + else + return 0; + } +} + + +int RefDesStringCompare( const wxString& strFWord, const wxString& strSWord ) +{ + // The different sections of the two strings + wxString strFWordBeg, strFWordMid, strFWordEnd; + wxString strSWordBeg, strSWordMid, strSWordEnd; + + // Split the two strings into separate parts + SplitString( strFWord, &strFWordBeg, &strFWordMid, &strFWordEnd ); + SplitString( strSWord, &strSWordBeg, &strSWordMid, &strSWordEnd ); + + // Compare the Beginning section of the strings + int isEqual = strFWordBeg.CmpNoCase( strSWordBeg ); + + if( isEqual > 0 ) + return 1; + else if( isEqual < 0 ) + return -1; + else + { + // If the first sections are equal compare their digits + long lFirstDigit = 0; + long lSecondDigit = 0; + strFWordMid.ToLong( &lFirstDigit ); strSWordMid.ToLong( &lSecondDigit ); if( lFirstDigit > lSecondDigit ) - iReturn = 1; + return 1; else if( lFirstDigit < lSecondDigit ) - iReturn = -1; + return -1; + // If the first two sections are equal compare the endings else - { - // If the first two sections are equal compare the endings - isEqual = strFWordEnd.CmpNoCase( strSWordEnd ); - - if( isEqual > 0 ) - iReturn = 1; - else if( isEqual < 0 ) - iReturn = -1; - else - iReturn = 0; - } + return strFWordEnd.CmpNoCase( strSWordEnd ); } - - return iReturn; } @@ -420,6 +505,8 @@ int SplitString( wxString strToSplit, wxString* strDigits, wxString* strEnd ) { + static const wxString separators( wxT( ".," ) ); + // Clear all the return strings strBeginning->Empty(); strDigits->Empty(); @@ -453,7 +540,7 @@ int SplitString( wxString strToSplit, for( ; ii >= 0; ii-- ) { - if( !isdigit( strToSplit[ii] ) ) + if( !isdigit( strToSplit[ii] ) && separators.Find( strToSplit[ii] ) < 0 ) break; } diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 356f612467..3ad3839bfe 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -120,8 +120,6 @@ set( EESCHEMA_SRCS eeschema_config.cpp erc.cpp events_called_functions_for_edit.cpp - fields_editor_table_column.cpp - fields_editor_table_model.cpp files-io.cpp find.cpp generate_alias_info.cpp diff --git a/eeschema/component_references_lister.cpp b/eeschema/component_references_lister.cpp index e27599aff2..c869308b6c 100644 --- a/eeschema/component_references_lister.cpp +++ b/eeschema/component_references_lister.cpp @@ -703,13 +703,7 @@ void SCH_REFERENCE::Annotate() m_Ref += '?'; else { - // To avoid a risk of duplicate, for power components - // the ref number is 0nnn instead of nnn. - // Just because sometimes only power components are annotated - if( GetLibPart() && GetLibPart()->IsPower() ) - m_Ref = TO_UTF8( GetRef() << "0" << m_NumRef ); - else - m_Ref = TO_UTF8( GetRef() << m_NumRef ); + m_Ref = TO_UTF8( GetRef() << GetRefNumber() ); } m_RootCmp->SetRef( &m_SheetPath, FROM_UTF8( m_Ref.c_str() ) ); diff --git a/eeschema/dialogs/dialog_fields_editor_global.cpp b/eeschema/dialogs/dialog_fields_editor_global.cpp index 0cc01f53a5..5e6c443ee6 100644 --- a/eeschema/dialogs/dialog_fields_editor_global.cpp +++ b/eeschema/dialogs/dialog_fields_editor_global.cpp @@ -23,20 +23,22 @@ */ -#include #include -#include -#include -#include +#include #include +#include +#include +#include #include #include #include +#include +#include + #include "dialog_fields_editor_global.h" -#include // Create and show fields editor @@ -47,288 +49,436 @@ void InvokeDialogCreateBOMEditor( SCH_EDIT_FRAME* aCaller ) } +#define FIELD_NAME_COLUMN 0 +#define SHOW_FIELD_COLUMN 1 +#define GROUP_BY_COLUMN 2 + +#define QUANTITY_COLUMN ( GetNumberCols() - 1 ) + + +// Indicator that multiple values exist in child rows +#define ROW_MULT_ITEMS wxString( "< ... >" ) + + +class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase +{ +protected: + // The data model is fundamentally m_componentRefs X m_fieldNames. + + SCH_REFERENCE_LIST m_componentRefs; + std::vector m_fieldNames; + + // However, the grid view can vary in two ways: + // 1) the componentRefs can be grouped into fewer rows + // 2) some columns can be hidden + // + // We handle (1) here (ie: a table row maps to a group, and the table is rebuilt + // when the groupings change), and we let the wxGrid handle (2) (ie: the number + // of columns is constant but are hidden/shown by the wxGrid control). + + std::vector< std::vector > m_rows; + + // Data store + // A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue + std::map< timestamp_t, std::map > m_dataStore; + +public: + FIELDS_EDITOR_GRID_DATA_MODEL( SCH_REFERENCE_LIST& aComponentList ) + { + m_componentRefs = aComponentList; + m_componentRefs.SplitReferences(); + } + + + void AddColumn( const wxString& aFieldName ) + { + m_fieldNames.push_back( aFieldName ); + + for( int i = 0; i < m_componentRefs.GetCount(); ++i ) + { + SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp(); + timestamp_t compID = comp->GetTimeStamp(); + + m_dataStore[ compID ][ aFieldName ] = comp->GetFieldText( aFieldName ); + } + } + + + int GetNumberRows() override { return m_rows.size(); } + + // Columns are fieldNames + quantity column + int GetNumberCols() override { return m_fieldNames.size() + 1; } + + + wxString GetColLabelValue( int aCol ) override + { + if( aCol == QUANTITY_COLUMN ) + return _T( "Qty" ); + else + return m_fieldNames[ aCol ]; + } + + + 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 + { + return GetValue( m_rows[ aRow ], aCol ); + } + + + wxString GetValue( std::vector& group, int aCol ) + { + std::vector rootReferences; + wxString fieldValue; + + for( const auto& ref : group ) + { + if( aCol == REFERENCE || aCol == QUANTITY_COLUMN ) + { + rootReferences.push_back( ref.GetRef() << ref.GetRefNumber() ); + } + else // Other columns are either a single value or ROW_MULTI_ITEMS + { + timestamp_t compID = ref.GetComp()->GetTimeStamp(); + + if( &ref == &group.front() ) + fieldValue = m_dataStore[ compID ][ m_fieldNames[ aCol ] ]; + else if ( fieldValue != m_dataStore[ compID ][ m_fieldNames[ aCol ] ] ) + return ROW_MULT_ITEMS; + } + } + + if( aCol == REFERENCE || aCol == QUANTITY_COLUMN ) + { + // Remove duplicates (other units of multi-unit parts) + rootReferences.erase( std::unique( rootReferences.begin(), rootReferences.end() ), + rootReferences.end() ); + } + + if( aCol == REFERENCE ) + { + for( const auto& ref : rootReferences ) + { + if( fieldValue.length() ) + fieldValue += wxT( ", " ); + fieldValue += ref; + } + } + else if( aCol == QUANTITY_COLUMN ) + { + fieldValue = wxString::Format( wxT( "%d" ), ( int )rootReferences.size() ); + } + + return fieldValue; + } + + + void SetValue( int aRow, int aCol, const wxString &aValue ) override + { + if( aCol == REFERENCE || aCol == QUANTITY_COLUMN ) + return; // Can't modify references or quantity + + std::vector& rowGroup = m_rows[ aRow ]; + wxString fieldName = m_fieldNames[ aCol ]; + + for( const auto& ref : rowGroup ) + m_dataStore[ ref.GetComp()->GetTimeStamp() ][ fieldName ] = aValue; + } + + + static bool cmp( std::vector& lhGroup, std::vector& rhGroup, + FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending ) + { + // Empty rows always go to the bottom, whether ascending or descending + if( lhGroup.size() == 0 ) + return true; + else if( rhGroup.size() == 0 ) + return false; + + bool retVal; + + // Primary sort key is sortCol; secondary is always REFERENCE (column 0) + + wxString lhs = dataModel->GetValue( lhGroup, sortCol ); + wxString rhs = dataModel->GetValue( rhGroup, sortCol ); + + if( lhs == rhs || sortCol == REFERENCE ) + { + wxString lhRef = lhGroup[ 0 ].GetRef() + lhGroup[ 0 ].GetRefNumber(); + wxString rhRef = rhGroup[ 0 ].GetRef() + rhGroup[ 0 ].GetRefNumber(); + retVal = RefDesStringCompare( lhRef, rhRef ) < 0; + } + else + retVal = ValueStringCompare( lhs, rhs ) < 0; + + if( ascending ) + return retVal; + else + return !retVal; + } + + + void Sort( int aColumn, bool ascending ) + { + if( aColumn < 0 ) + aColumn = 0; + + std::sort( m_rows.begin(), m_rows.end(), + [ this, aColumn, ascending ]( std::vector& lhs, + std::vector& rhs ) -> bool + { + return cmp( lhs, rhs, this, aColumn, ascending ); + } ); + } + + + bool match( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef, + wxCheckBox* groupComponentsBox, wxDataViewListCtrl* fieldsCtrl ) + { + // Units of same component always match + if( lhRef.GetRef() == rhRef.GetRef() && lhRef.GetRefNumber() == rhRef.GetRefNumber() ) + return true; + + // If we're not grouping, then nothing else matches + if( !groupComponentsBox->GetValue() ) + return false; + + bool matchFound = false; + + // First check the reference column. This can be done directly out of the + // SCH_REFERENCEs as the references can't be edited in the grid. + if( fieldsCtrl->GetToggleValue( REFERENCE, GROUP_BY_COLUMN ) ) + { + // if we're grouping by reference, then only the prefix must match + if( lhRef.GetRef() != rhRef.GetRef() ) + return false; + + matchFound = true; + } + + timestamp_t lhRefID = lhRef.GetComp()->GetTimeStamp(); + timestamp_t rhRefID = rhRef.GetComp()->GetTimeStamp(); + + // Now check all the other columns. This must be done out of the dataStore + // for the refresh button to work after editing. + for( int i = REFERENCE + 1; i < fieldsCtrl->GetItemCount(); ++i ) + { + if( !fieldsCtrl->GetToggleValue( i, GROUP_BY_COLUMN ) ) + continue; + + wxString fieldName = fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ); + + if( m_dataStore[ lhRefID ][ fieldName ] != m_dataStore[ rhRefID ][ fieldName ] ) + return false; + + matchFound = true; + } + + return matchFound; + } + + + void RebuildRows( wxCheckBox* groupComponentsBox, wxDataViewListCtrl* fieldsCtrl ) + { + m_rows.clear(); + + for( int i = 0; i < m_componentRefs.GetCount(); ++i ) + { + SCH_REFERENCE compRef = m_componentRefs[ i ]; + bool matchFound = false; + + // See if we already have a group which this component fits into + for( auto& rowGroup : m_rows ) + { + // group members are by definition all matching, so just check + // against the first member + if( match( rowGroup[ 0 ], compRef, groupComponentsBox, fieldsCtrl ) ) + { + matchFound = true; + rowGroup.push_back( compRef ); + break; + } + } + + if( !matchFound ) + { + std::vector newGroup; + newGroup.push_back( compRef ); + m_rows.push_back( newGroup ); + } + } + + for( auto& rowGroup : m_rows ) + { + std::sort( rowGroup.begin(), rowGroup.end(), + []( SCH_REFERENCE& lhs, SCH_REFERENCE& rhs ) -> bool + { + wxString lhRef( lhs.GetRef() << lhs.GetRefNumber() ); + wxString rhRef( rhs.GetRef() << rhs.GetRefNumber() ); + return RefDesStringCompare( lhRef, rhRef ) < 0; + } ); + } + } + + + void ApplyData( SCH_EDIT_FRAME* aParent ) + { + for( int i = 0; i < m_componentRefs.GetCount(); ++i ) + { + SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp(); + + aParent->SetCurrentSheet( m_componentRefs[ i ].GetSheetPath() ); + aParent->SaveCopyInUndoList( comp, UR_CHANGED, true ); + + std::map& fieldStore = m_dataStore[ comp->GetTimeStamp() ]; + + for( int j = 0; j < comp->GetFieldCount(); ++j ) + { + SCH_FIELD* field = comp->GetField( j ); + auto fieldStoreData = fieldStore.find( field->GetName() ); + if( fieldStoreData != fieldStore.end() ) + field->SetText( fieldStoreData->second ); + } + } + } +}; + + DIALOG_FIELDS_EDITOR_GLOBAL::DIALOG_FIELDS_EDITOR_GLOBAL( SCH_EDIT_FRAME* parent ) : DIALOG_FIELDS_EDITOR_GLOBAL_BASE( parent ), m_parent( parent ) { - m_bom = FIELDS_EDITOR_TABLE_MODEL::Create(); + // Get all components from the list of schematic sheets + SCH_SHEET_LIST sheets( g_RootSheet ); + sheets.GetComponents( m_componentRefs, false ); - auto nameColumn = m_columnListCtrl->AppendTextColumn( _( "Field" ) ); + m_bRefresh->SetBitmap( KiBitmap( refresh_xpm ) ); - auto showColumn = m_columnListCtrl->AppendToggleColumn( - _( "Show" ), - wxDATAVIEW_CELL_ACTIVATABLE, - 100 ); + m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT ); + m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 40, wxALIGN_CENTER, 0 ); + m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 60, wxALIGN_CENTER, 0 ); - auto sortColumn = m_columnListCtrl->AppendToggleColumn( - _( "Sort" ), - wxDATAVIEW_CELL_ACTIVATABLE, - 100 ); + // The fact that we're a list should keep the control from reserving space for the + // expander buttons... but it doesn't. Fix by forcing the indent to 0. + m_fieldsCtrl->SetIndent( 0 ); + m_dataModel = new FIELDS_EDITOR_GRID_DATA_MODEL( m_componentRefs ); - // Read all components - LoadComponents(); + LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel - LoadColumnNames(); - ReloadColumns(); + m_dataModel->RebuildRows( m_groupComponentsBox, m_fieldsCtrl ); + m_dataModel->Sort( 0, true ); - m_bom->ReloadTable(); + m_grid->UseNativeColHeader( true ); + m_grid->SetTable( m_dataModel, true ); - // Set default column widths for fields table - showColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE ); - showColumn->SetResizeable( false ); + // add Cut, Copy, and Paste to wxGrid + m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) ); - nameColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE ); - nameColumn->SetResizeable( true ); + // give a bit more room for editing + m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 2 ); - sortColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE ); - sortColumn->SetResizeable( false ); - - - // Reference column is either single reference or a list of references. - // Autosize can fill the window in the case of a list so use a fixed width. - // wxCOL_WIDTH_DEFAULT is wxDVC_DEFAULT_WIDTH on all platforms and too small. - auto refcol = m_bomView->GetColumn( 0 ); - refcol->SetWidth( wxDVC_DEFAULT_WIDTH * 2 ); - refcol->SetResizeable( true ); - - // Set default column widths for BOM table - for( unsigned int ii = 1; ii < m_bomView->GetColumnCount(); ii++ ) + // set column attributes + for( int i = 0; i < m_dataModel->GetRowsCount(); ++i ) { - auto col = m_bomView->GetColumn( ii ); - - if( !col ) - continue; - - col->SetWidth( wxCOL_WIDTH_AUTOSIZE ); - col->SetResizeable( true ); + m_grid->SetReadOnly( i, 0 ); // references + m_grid->SetReadOnly( i, m_dataModel->GetColsCount() - 1 ); // quantities } + m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 ); // quantities + m_grid->SetColMinimalWidth( 0, 100 ); // references + m_grid->SetColMinimalWidth( m_dataModel->GetColsCount() - 1, 40 ); // quantities + m_grid->AutoSizeColumns( false ); + + m_grid->SetGridCursor( 0, 1 ); + m_grid->SetFocus(); + + m_sdbSizer1OK->SetDefault(); Layout(); - SetSizeInDU( 400, 240 ); + SetSizeInDU( 500, 300 ); Center(); + + // Connect Events + m_grid->Connect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this ); } DIALOG_FIELDS_EDITOR_GLOBAL::~DIALOG_FIELDS_EDITOR_GLOBAL() { - // Nothing to do. + // Disconnect Events + m_grid->Disconnect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this ); + + // Delete the GRID_TRICKS. + m_grid->PopEventHandler( true ); + + // we gave ownership of m_dataModel to the wxGrid... } -void DIALOG_FIELDS_EDITOR_GLOBAL::OnCloseButton( wxCommandEvent& event ) +bool DIALOG_FIELDS_EDITOR_GLOBAL::TransferDataFromWindow() { - // DIALOG_FIELDS_EDITOR_GLOBAL::OnDialogClosed() will be called, - // when closing this dialog. - // The default wxID_CANCEL handler is not suitable for us, - // because it calls DIALOG_SHIM::EndQuasiModal() without calling - // DIALOG_FIELDS_EDITOR_GLOBAL::OnDialogClosed() - Close(); -} + // Commit any pending in-place edits and close the editor + m_grid->DisableCellEditControl(); + if( !wxDialog::TransferDataFromWindow() ) + return false; -bool DIALOG_FIELDS_EDITOR_GLOBAL::CanCloseDialog() -{ - if( !m_bom->HaveFieldsChanged() ) - return true; + SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet(); - int result = DisplayExitDialog( this, _( "Changes exist in component table" ) ); + m_dataModel->ApplyData( m_parent ); + m_parent->OnModify(); - switch( result ) - { - case wxID_CANCEL: - return false; - - case wxID_NO: - break; - - case wxID_YES: - ApplyAllChanges(); - break; - } + // Reset the view to where we left the user + m_parent->SetCurrentSheet( currentSheet ); + m_parent->Refresh(); return true; } -void DIALOG_FIELDS_EDITOR_GLOBAL::OnDialogClosed( wxCloseEvent& event ) +void DIALOG_FIELDS_EDITOR_GLOBAL::AddField( const wxString& aFieldName, + bool defaultShow, bool defaultSortBy ) { - if( !CanCloseDialog() ) - { - event.Veto(); - } - else - // Mandatory to call DIALOG_SHIM::OnCloseWindow( wxCloseEvent& aEvent ) - // and actually close the dialog - event.Skip(); + m_dataModel->AddColumn( aFieldName ); + + wxVector fieldsCtrlDataLine; + + fieldsCtrlDataLine.push_back( wxVariant( aFieldName ) ); + fieldsCtrlDataLine.push_back( wxVariant( defaultShow ) ); + fieldsCtrlDataLine.push_back( wxVariant( defaultSortBy ) ); + + m_fieldsCtrl->AppendItem( fieldsCtrlDataLine ); } -/* Struct for keeping track of schematic sheet changes - * Stores: - * SHEET_PATH - Schematic to apply changes to - * PICKED_ITEMS_LIST - List of changes to apply +/** + * Constructs the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all + * field names in use. */ - -typedef struct +void DIALOG_FIELDS_EDITOR_GLOBAL::LoadFieldNames() { - SCH_SHEET_PATH path; - PICKED_ITEMS_LIST items; -} SheetUndoList; + std::set userFieldNames; - -void DIALOG_FIELDS_EDITOR_GLOBAL::ApplyAllChanges() -{ - if( !m_bom->HaveFieldsChanged() ) - return; - - /** - * As we may be saving changes across multiple sheets, - * we need to first determine which changes need to be made to which sheet. - * To this end, we perform the following: - * 1. Save the "path" of the currently displayed sheet - * 2. Create a MAP of changes that need to be made - * 3. Push UNDO actions to appropriate sheets - * 4. Perform all the update actions - * 5. Reset the view to the current sheet - */ - - auto currentSheet = m_parent->GetCurrentSheet(); - - //! Create a map of changes required for each sheet - std::map undoSheetMap; - - // List of components that have changed - auto changed = m_bom->GetChangedComponents(); - - ITEM_PICKER picker; - - // Iterate through each of the components that were changed - for( const auto& ref : changed ) + for( int i = 0; i < m_componentRefs.GetCount(); ++i ) { - // Extract the SCH_COMPONENT* object - auto cmp = ref.GetComp(); + SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp(); - wxString path = ref.GetSheetPath().Path(); - - // Push the component into the picker list - picker = ITEM_PICKER( cmp, UR_CHANGED ); - picker.SetFlags( cmp->GetFlags() ); - - /* - * If there is not currently an undo list for the given sheet, - * create an empty one - */ - - if( undoSheetMap.count( path ) == 0 ) - { - SheetUndoList newList; - - newList.path = ref.GetSheetPath(); - - undoSheetMap[path] = newList; - } - - auto& pickerList = undoSheetMap[path]; - - pickerList.items.PushItem( picker ); + for( int j = MANDATORY_FIELDS; j < comp->GetFieldCount(); ++j ) + userFieldNames.insert( comp->GetField( j )->GetName() ); } - // Iterate through each sheet that needs updating - for( auto it = undoSheetMap.begin(); it != undoSheetMap.end(); ++it ) - { - auto undo = it->second; + AddField( _( "Reference" ), true, true ); + AddField( _( "Value" ), true, true ); + AddField( _( "Footprint" ), true, true ); + AddField( _( "Datasheet" ), true, false ); - m_parent->SetCurrentSheet( undo.path ); - m_parent->SaveCopyInUndoList( undo.items, UR_CHANGED ); - m_parent->OnModify(); - } - - // Make all component changes - m_bom->ApplyFieldChanges(); - - // Redraw the current sheet and mark as dirty - m_parent->Refresh(); - m_parent->OnModify(); - - // Reset the view to where we left the user - m_parent->SetCurrentSheet(currentSheet); - - // Instruct the table to set the current values as the new backup values - m_bom->SetBackupPoint(); -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::UpdateTitle() -{ - wxString title; - - - if( m_bom->GetColumnGrouping() ) - { - title.Printf ( _( "Symbol Table - %u symbols in %u groups" ), - m_bom->ComponentCount(), - (unsigned int) m_bom->Groups.size() ); - } - else - title.Printf ( _( "Symbol Table - %u components" ), - m_bom->ComponentCount() ); - - unsigned int count = m_bom->CountChangedComponents(); - - if( count > 0 ) - title += wxString::Format( _( " - %u changed" ), count ); - - // Update title only if it has changed, to avoid flicker created by - // useless update, for instance when moving the mouse, because UpdateTitle() - // is called by a wxUpdateUIEvent: - if( GetTitle() != title ) - SetTitle( title ); -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::LoadComponents() -{ - if( !m_parent ) return; - - // List of component objects - SCH_REFERENCE_LIST refs; - - // Generate a list of schematic sheets - SCH_SHEET_LIST sheets( g_RootSheet ); - sheets.GetComponents( refs, false ); - - // Pass the references through to the model - m_bom->SetComponents( refs, m_parent->GetTemplateFieldNames() ); -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::LoadColumnNames() -{ - m_columnListCtrl->DeleteAllItems(); - - wxVector< wxVariant > data; - - for( auto* col : m_bom->ColumnList.Columns ) - { - if( nullptr == col ) - continue; - - data.clear(); - - data.push_back( wxVariant( col->Title() ) ); // Column title (string) - data.push_back( wxVariant( col->IsVisible() ) ); // Column visibility (bool) - data.push_back( wxVariant( col->IsUsedToSort() ) ); // Column is used to sort - - m_columnListCtrl->AppendItem( data ); - } -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::ReloadColumns() -{ - m_bom->AttachTo( m_bomView ); - UpdateTitle(); + for( auto fieldName : userFieldNames ) + AddField( fieldName, true, false ); } @@ -336,41 +486,25 @@ void DIALOG_FIELDS_EDITOR_GLOBAL::OnColumnItemToggled( wxDataViewEvent& event ) { wxDataViewItem item = event.GetItem(); - int row = m_columnListCtrl->ItemToRow( item ); + int row = m_fieldsCtrl->ItemToRow( item ); int col = event.GetColumn(); - if( row == wxNOT_FOUND || row < 0 || row >= (int) m_bom->ColumnCount() ) - return; - - FIELDS_EDITOR_COLUMN* bomColumn = m_bom->ColumnList.GetColumnByIndex( row ); - - if( nullptr == bomColumn ) - return; - - bool bValue = m_columnListCtrl->GetToggleValue( row, col ); - switch ( col ) { default: break; - case 1: // Column visibility - bomColumn->SetVisible( bValue ); - - // Insert a new column - if( bValue ) - { - m_bom->AddColumn( bomColumn ); - } + case SHOW_FIELD_COLUMN: + if( m_fieldsCtrl->GetToggleValue( row, col ) ) + m_grid->ShowCol( row ); else - { - m_bom->RemoveColumn( bomColumn ); - } + m_grid->HideCol( row ); // grid's columns map to fieldsCtrl's rows break; - case 2: // Column used to sort - bomColumn->SetUsedToSort( bValue ); - m_bom->ReloadTable(); + case GROUP_BY_COLUMN: + m_dataModel->RebuildRows( m_groupComponentsBox, m_fieldsCtrl ); + m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() ); + m_grid->ForceRefresh(); break; } } @@ -378,78 +512,62 @@ void DIALOG_FIELDS_EDITOR_GLOBAL::OnColumnItemToggled( wxDataViewEvent& event ) void DIALOG_FIELDS_EDITOR_GLOBAL::OnGroupComponentsToggled( wxCommandEvent& event ) { - bool group = m_groupComponentsBox->GetValue(); - - m_bom->SetColumnGrouping( group ); - m_bom->ReloadTable(); - - Update(); + m_dataModel->RebuildRows( m_groupComponentsBox, m_fieldsCtrl ); + m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() ); + m_grid->ForceRefresh(); } -void DIALOG_FIELDS_EDITOR_GLOBAL::OnUpdateUI( wxUpdateUIEvent& event ) +void DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort( wxGridEvent& aEvent ) { - m_regroupComponentsButton->Enable( m_bom->GetColumnGrouping() ); + int sortCol = aEvent.GetCol(); + bool ascending; - bool changes = m_bom->HaveFieldsChanged(); + // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the + // event, and if we ask it will give us pre-event info. + if( m_grid->IsSortingBy( sortCol ) ) + // same column; invert ascending + ascending = !m_grid->IsSortOrderAscending(); + else + // different column; start with ascending + ascending = true; - m_applyChangesButton->Enable( changes ); - m_revertChangesButton->Enable( changes ); - - UpdateTitle(); + m_dataModel->Sort( sortCol, ascending ); } -void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableValueChanged( wxDataViewEvent& event ) +void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableValueChanged( wxGridEvent& event ) { - Update(); + m_grid->ForceRefresh(); } void DIALOG_FIELDS_EDITOR_GLOBAL::OnRegroupComponents( wxCommandEvent& event ) { - m_bom->ReloadTable(); - Update(); + m_dataModel->RebuildRows( m_groupComponentsBox, m_fieldsCtrl ); + m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() ); + m_grid->ForceRefresh(); } -void DIALOG_FIELDS_EDITOR_GLOBAL::OnApplyFieldChanges( wxCommandEvent& event ) -{ - ApplyAllChanges(); - Update(); -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::OnRevertFieldChanges( wxCommandEvent& event ) -{ - if( m_bom->HaveFieldsChanged() ) - { - if( IsOK( this, _( "Revert all symbol table changes?" ) ) ) - { - m_bom->RevertFieldChanges(); - Update(); - } - } -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableItemActivated( wxDataViewEvent& event ) +void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableItemContextMenu( wxGridEvent& event ) { /* TODO - * - Focus on component selected in SCH_FRAME - */ - - event.Skip(); -} - - -void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableItemContextMenu( wxDataViewEvent& event ) -{ - /* TODO - * - Display contect menu - * - Option to revert local changes if changes have been made * - Option to select footprint if FOOTPRINT column selected */ event.Skip(); } + + +void DIALOG_FIELDS_EDITOR_GLOBAL::OnSizeFieldList( wxSizeEvent& event ) +{ + int newWidth = event.GetSize().GetX(); + + newWidth -= m_fieldsCtrl->GetColumn( 1 )->GetWidth(); + newWidth -= m_fieldsCtrl->GetColumn( 2 )->GetWidth(); + + m_fieldsCtrl->GetColumn( 0 )->SetWidth( newWidth - 8 ); + + event.Skip(); +} diff --git a/eeschema/dialogs/dialog_fields_editor_global.h b/eeschema/dialogs/dialog_fields_editor_global.h index 926fdb700f..7cd25ef6eb 100644 --- a/eeschema/dialogs/dialog_fields_editor_global.h +++ b/eeschema/dialogs/dialog_fields_editor_global.h @@ -2,7 +2,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2017 Oliver Walters - * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017-2018 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 @@ -22,77 +22,46 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/** - * @file eeschema/dialogs/dialog_fields_editor_global.cpp - * @brief Dialog box for creating bom and other documents from generic netlist. - */ - #ifndef DIALOG_FIELDS_EDITOR_GLOBAL_H #define DIALOG_FIELDS_EDITOR_GLOBAL_H -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include + +class SCH_EDIT_FRAME; +class FIELDS_EDITOR_GRID_DATA_MODEL; + class DIALOG_FIELDS_EDITOR_GLOBAL : public DIALOG_FIELDS_EDITOR_GLOBAL_BASE { - public: DIALOG_FIELDS_EDITOR_GLOBAL( SCH_EDIT_FRAME* parent ); virtual ~DIALOG_FIELDS_EDITOR_GLOBAL(); + bool TransferDataFromWindow() override; + private: - //! Parent object (Schematic) SCH_EDIT_FRAME* m_parent; - FIELDS_EDITOR_TABLE_MODEL::MODEL_PTR m_bom; + SCH_REFERENCE_LIST m_componentRefs; + FIELDS_EDITOR_GRID_DATA_MODEL* m_dataModel; - void LoadComponents(); + void AddField( const wxString& aFieldName, bool defaultShow, bool defaultSortBy ); + void LoadFieldNames(); - void LoadColumnNames(); - void ReloadColumns(); + bool Match( SCH_REFERENCE& aRef, SCH_REFERENCE& bRef, bool groupComponents ); + void RebuildRows(); - void ApplyAllChanges(); + void OnColSort( wxGridEvent& aEvent ); - // Checkbox event callbacks virtual void OnColumnItemToggled( wxDataViewEvent& event ) override; virtual void OnGroupComponentsToggled( wxCommandEvent& event ) override; - - virtual void OnRevertFieldChanges( wxCommandEvent& event ) override; - - virtual void OnApplyFieldChanges( wxCommandEvent& event ) override; - virtual void OnRegroupComponents( wxCommandEvent& event ) override; - - // Called after a value in the table has changed - virtual void OnTableValueChanged( wxDataViewEvent& event ) override; - - // Called when a cell is left-clicked - virtual void OnTableItemActivated( wxDataViewEvent& event ) override; - - // Called when a cell is right-clicked - virtual void OnTableItemContextMenu( wxDataViewEvent& event ) override; - - // Called when the dialog is closed - virtual void OnDialogClosed( wxCloseEvent& event ) override; - virtual void OnCloseButton( wxCommandEvent& event ) override; - - bool CanCloseDialog(); - - void UpdateTitle( void ); - - virtual void OnUpdateUI( wxUpdateUIEvent& event ) override; - + virtual void OnTableValueChanged( wxGridEvent& event ) override; + virtual void OnTableItemContextMenu( wxGridEvent& event ) override; + virtual void OnSizeFieldList( wxSizeEvent& event ) override; }; #endif /* DIALOG_FIELDS_EDITOR_GLOBAL_H */ diff --git a/eeschema/dialogs/dialog_fields_editor_global_base.cpp b/eeschema/dialogs/dialog_fields_editor_global_base.cpp index 056d011e50..36aafe714b 100644 --- a/eeschema/dialogs/dialog_fields_editor_global_base.cpp +++ b/eeschema/dialogs/dialog_fields_editor_global_base.cpp @@ -1,8 +1,8 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Aug 4 2017) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // -// PLEASE DO "NOT" EDIT THIS FILE! +// PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #include "dialog_fields_editor_global_base.h" @@ -23,7 +23,7 @@ DIALOG_FIELDS_EDITOR_GLOBAL_BASE::DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* pa wxBoxSizer* bSizer7; bSizer7 = new wxBoxSizer( wxVERTICAL ); - m_splitter1 = new wxSplitterWindow( m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D ); + m_splitter1 = new wxSplitterWindow( m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3DSASH ); m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::m_splitter1OnIdle ), NULL, this ); m_splitter1->SetMinimumPaneSize( 120 ); @@ -31,34 +31,33 @@ DIALOG_FIELDS_EDITOR_GLOBAL_BASE::DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* pa wxBoxSizer* bSizer6; bSizer6 = new wxBoxSizer( wxVERTICAL ); - wxStaticBoxSizer* sbSizer1; - sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Options") ), wxVERTICAL ); + wxBoxSizer* bSizer8; + bSizer8 = new wxBoxSizer( wxHORIZONTAL ); - m_groupComponentsBox = new wxCheckBox( sbSizer1->GetStaticBox(), OPT_GROUP_COMPONENTS, _("Group symbols"), wxDefaultPosition, wxDefaultSize, 0 ); + m_groupComponentsBox = new wxCheckBox( m_leftPanel, OPT_GROUP_COMPONENTS, _("Group symbols"), wxDefaultPosition, wxDefaultSize, 0 ); m_groupComponentsBox->SetValue(true); m_groupComponentsBox->SetToolTip( _("Group components together based on common properties") ); - sbSizer1->Add( m_groupComponentsBox, 0, wxALL|wxEXPAND, 5 ); - - m_regroupComponentsButton = new wxButton( sbSizer1->GetStaticBox(), wxID_ANY, _("Regroup symbols"), wxDefaultPosition, wxDefaultSize, 0 ); - sbSizer1->Add( m_regroupComponentsButton, 0, wxALL|wxEXPAND, 5 ); + bSizer8->Add( m_groupComponentsBox, 0, wxALL|wxEXPAND, 5 ); - bSizer6->Add( sbSizer1, 0, wxEXPAND, 5 ); + bSizer8->Add( 0, 0, 1, wxEXPAND, 5 ); + + m_bRefresh = new wxBitmapButton( m_leftPanel, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW ); + m_bRefresh->SetMinSize( wxSize( 30,28 ) ); + + bSizer8->Add( m_bRefresh, 0, wxALIGN_CENTER_VERTICAL, 5 ); + + + bSizer6->Add( bSizer8, 0, wxALL|wxBOTTOM|wxEXPAND|wxTOP, 3 ); wxBoxSizer* bSizer9; bSizer9 = new wxBoxSizer( wxVERTICAL ); - wxStaticBoxSizer* m_fieldListSizer; - m_fieldListSizer = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Fields") ), wxVERTICAL ); + m_fieldsCtrl = new wxDataViewListCtrl( m_leftPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); + m_fieldsCtrl->SetMinSize( wxSize( -1,250 ) ); - m_columnListCtrl = new wxDataViewListCtrl( m_fieldListSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); - m_columnListCtrl->SetMinSize( wxSize( -1,250 ) ); - - m_fieldListSizer->Add( m_columnListCtrl, 1, wxALL|wxEXPAND, 5 ); - - - bSizer9->Add( m_fieldListSizer, 1, wxEXPAND, 5 ); + bSizer9->Add( m_fieldsCtrl, 1, wxALL|wxEXPAND, 5 ); bSizer6->Add( bSizer9, 5, wxEXPAND, 5 ); @@ -71,41 +70,53 @@ DIALOG_FIELDS_EDITOR_GLOBAL_BASE::DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* pa wxBoxSizer* bSizer5; bSizer5 = new wxBoxSizer( wxVERTICAL ); - m_bomView = new wxDataViewCtrl( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES ); - m_bomView->SetMinSize( wxSize( 450,250 ) ); + m_grid = new wxGrid( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); - bSizer5->Add( m_bomView, 1, wxALL|wxEXPAND, 5 ); + // Grid + m_grid->CreateGrid( 5, 5 ); + m_grid->EnableEditing( true ); + m_grid->EnableGridLines( true ); + m_grid->EnableDragGridSize( false ); + m_grid->SetMargins( 0, 0 ); + + // Columns + m_grid->EnableDragColMove( false ); + m_grid->EnableDragColSize( true ); + m_grid->SetColLabelSize( 20 ); + m_grid->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Rows + m_grid->EnableDragRowSize( false ); + m_grid->SetRowLabelSize( 0 ); + m_grid->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); + + // Label Appearance + + // Cell Defaults + m_grid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP ); + bSizer5->Add( m_grid, 1, wxALL|wxEXPAND, 5 ); m_panel4->SetSizer( bSizer5 ); m_panel4->Layout(); bSizer5->Fit( m_panel4 ); - m_splitter1->SplitVertically( m_leftPanel, m_panel4, 231 ); + m_splitter1->SplitVertically( m_leftPanel, m_panel4, 200 ); bSizer7->Add( m_splitter1, 1, wxEXPAND, 5 ); m_panel->SetSizer( bSizer7 ); m_panel->Layout(); bSizer7->Fit( m_panel ); - bSizer61->Add( m_panel, 1, wxEXPAND | wxALL, 5 ); + bSizer61->Add( m_panel, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 ); - wxBoxSizer* bSizerButtonsBottom; - bSizerButtonsBottom = new wxBoxSizer( wxHORIZONTAL ); + m_sdbSizer1 = new wxStdDialogButtonSizer(); + m_sdbSizer1OK = new wxButton( this, wxID_OK ); + m_sdbSizer1->AddButton( m_sdbSizer1OK ); + m_sdbSizer1Cancel = new wxButton( this, wxID_CANCEL ); + m_sdbSizer1->AddButton( m_sdbSizer1Cancel ); + m_sdbSizer1->Realize(); - m_applyChangesButton = new wxButton( this, wxID_ANY, _("Apply Changes"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizerButtonsBottom->Add( m_applyChangesButton, 0, wxALL, 5 ); - - m_revertChangesButton = new wxButton( this, wxID_ANY, _("Revert Changes"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizerButtonsBottom->Add( m_revertChangesButton, 0, wxALL, 5 ); - - - bSizerButtonsBottom->Add( 0, 0, 1, wxEXPAND, 5 ); - - m_closeButton = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, 0 ); - bSizerButtonsBottom->Add( m_closeButton, 0, wxALL, 5 ); - - - bSizer61->Add( bSizerButtonsBottom, 0, wxEXPAND, 5 ); + bSizer61->Add( m_sdbSizer1, 0, wxEXPAND, 5 ); bHorizontalSizer->Add( bSizer61, 1, wxEXPAND, 5 ); @@ -118,38 +129,26 @@ DIALOG_FIELDS_EDITOR_GLOBAL_BASE::DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* pa this->Centre( wxBOTH ); // Connect Events - this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnDialogClosed ) ); - this->Connect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnUpdateUI ) ); m_groupComponentsBox->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnGroupComponentsToggled ), NULL, this ); - m_regroupComponentsButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRegroupComponents ), NULL, this ); - m_columnListCtrl->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnColumnItemToggled ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_COLUMN_REORDERED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnBomColumReordered ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnBomColumnSorted ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemActivated ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemContextMenu ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableValueChanged ), NULL, this ); - m_bomView->Connect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnSelectionChanged ), NULL, this ); - m_applyChangesButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnApplyFieldChanges ), NULL, this ); - m_revertChangesButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRevertFieldChanges ), NULL, this ); - m_closeButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnCloseButton ), NULL, this ); + m_bRefresh->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRegroupComponents ), NULL, this ); + m_fieldsCtrl->Connect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnColumnItemToggled ), NULL, this ); + m_fieldsCtrl->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnSizeFieldList ), NULL, this ); + m_grid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableValueChanged ), NULL, this ); + m_grid->Connect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemContextMenu ), NULL, this ); + m_sdbSizer1Cancel->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnCancel ), NULL, this ); + m_sdbSizer1OK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnOK ), NULL, this ); } DIALOG_FIELDS_EDITOR_GLOBAL_BASE::~DIALOG_FIELDS_EDITOR_GLOBAL_BASE() { // Disconnect Events - this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnDialogClosed ) ); - this->Disconnect( wxEVT_UPDATE_UI, wxUpdateUIEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnUpdateUI ) ); m_groupComponentsBox->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnGroupComponentsToggled ), NULL, this ); - m_regroupComponentsButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRegroupComponents ), NULL, this ); - m_columnListCtrl->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnColumnItemToggled ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_COLUMN_REORDERED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnBomColumReordered ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnBomColumnSorted ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemActivated ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_CONTEXT_MENU, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemContextMenu ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableValueChanged ), NULL, this ); - m_bomView->Disconnect( wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnSelectionChanged ), NULL, this ); - m_applyChangesButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnApplyFieldChanges ), NULL, this ); - m_revertChangesButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRevertFieldChanges ), NULL, this ); - m_closeButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnCloseButton ), NULL, this ); + m_bRefresh->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnRegroupComponents ), NULL, this ); + m_fieldsCtrl->Disconnect( wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, wxDataViewEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnColumnItemToggled ), NULL, this ); + m_fieldsCtrl->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnSizeFieldList ), NULL, this ); + m_grid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableValueChanged ), NULL, this ); + m_grid->Disconnect( wxEVT_GRID_CELL_RIGHT_CLICK, wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnTableItemContextMenu ), NULL, this ); + m_sdbSizer1Cancel->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnCancel ), NULL, this ); + m_sdbSizer1OK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::OnOK ), NULL, this ); } diff --git a/eeschema/dialogs/dialog_fields_editor_global_base.fbp b/eeschema/dialogs/dialog_fields_editor_global_base.fbp index 9cb289d078..0f5d7c6e8f 100644 --- a/eeschema/dialogs/dialog_fields_editor_global_base.fbp +++ b/eeschema/dialogs/dialog_fields_editor_global_base.fbp @@ -47,7 +47,7 @@ -1,-1 wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER DIALOG_SHIM; dialog_shim.h - Fields editor + Fields Editor @@ -61,7 +61,7 @@ - OnDialogClosed + @@ -87,7 +87,7 @@ - OnUpdateUI + bHorizontalSizer @@ -104,7 +104,7 @@ none 5 - wxEXPAND | wxALL + wxEXPAND|wxLEFT|wxRIGHT|wxTOP 1 1 @@ -234,12 +234,12 @@ Resizable 0.0 - 231 + 200 -1 1 wxSPLIT_VERTICAL - wxSP_3D + wxSP_3DSASH 0 @@ -354,18 +354,14 @@ wxVERTICAL none - 5 - wxEXPAND + 3 + wxALL|wxBOTTOM|wxEXPAND|wxTOP 0 - - wxID_ANY - Options + - sbSizer1 - wxVERTICAL - 1 + bSizer8 + wxHORIZONTAL none - 5 wxALL|wxEXPAND @@ -454,11 +450,21 @@ + + 5 + wxEXPAND + 1 + + 0 + protected + 0 + + 5 - wxALL|wxEXPAND + wxALIGN_CENTER_VERTICAL 0 - + 1 1 1 @@ -469,6 +475,7 @@ + 1 0 @@ -477,25 +484,28 @@ 1 0 0 + Dock 0 Left 1 1 + 0 0 + wxID_ANY - Regroup symbols + Refresh Grouping 0 0 - + 30,28 1 - m_regroupComponentsButton + m_bRefresh 1 @@ -503,10 +513,11 @@ 1 Resizable + 1 - - + wxBU_AUTODRAW + ; forward_declare 0 @@ -553,87 +564,72 @@ bSizer9 wxVERTICAL none - + 5 - wxEXPAND + wxALL|wxEXPAND 1 - + + + + 1 + 1 + + + 0 wxID_ANY - Fields - - m_fieldListSizer - wxVERTICAL - 1 - none + + -1,250 + m_fieldsCtrl + protected + + + + + + + + + + + + + + + + + + + + + + + + + + OnColumnItemToggled + + + + + + + + + + + + + + + + + + + + + + OnSizeFieldList - - 5 - wxALL|wxEXPAND - 1 - - - - 1 - 1 - - - 0 - wxID_ANY - - -1,250 - m_columnListCtrl - protected - - - - - - - - - - - - - - - - - - - - - - - - - - OnColumnItemToggled - - - - - - - - - - - - - - - - - - - - - - - - - @@ -721,52 +717,127 @@ bSizer5 wxVERTICAL none - + 5 wxALL|wxEXPAND 1 - + + 1 + 1 + 1 + 1 + + + + + 0 + 0 + + + 1 + + + wxALIGN_LEFT + + wxALIGN_TOP + 0 + 1 + wxALIGN_CENTRE + 20 + + wxALIGN_CENTRE + 5 + 1 + 0 + Dock + 0 + Left + 0 + 1 + 0 + 0 + 1 1 + 1 + + 1 + 0 0 wxID_ANY + + + + 0 + 0 + + 0 - 450,250 - m_bomView + + 0 + + 1 + m_grid + 1 + + protected + 1 + Resizable + wxALIGN_CENTRE + 0 + + wxALIGN_CENTRE + + 5 + 1 - wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES - + ; forward_declare + 0 - - - OnBomColumReordered - OnBomColumnSorted - OnTableItemActivated - - - - OnTableItemContextMenu - - - OnTableValueChanged - - - - - - OnSelectionChanged + OnTableValueChanged + + + OnTableItemContextMenu + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -801,285 +872,26 @@ 5 wxEXPAND 0 - + + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 - bSizerButtonsBottom - wxHORIZONTAL - none - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Apply Changes - - 0 - - - 0 - - 1 - m_applyChangesButton - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnApplyFieldChanges - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_ANY - Revert Changes - - 0 - - - 0 - - 1 - m_revertChangesButton - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnRevertFieldChanges - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - wxEXPAND - 1 - - 0 - protected - 0 - - - - 5 - wxALL - 0 - - 1 - 1 - 1 - 1 - - - - - - - - 1 - 0 - 1 - - 1 - 0 - 0 - Dock - 0 - Left - 1 - - 1 - - 0 - 0 - wxID_CANCEL - Close - - 0 - - - 0 - - 1 - m_closeButton - 1 - - - protected - 1 - - Resizable - 1 - - - - 0 - - - wxFILTER_NONE - wxDefaultValidator - - - - - OnCloseButton - - - - - - - - - - - - - - - - - - - - - - - - - + m_sdbSizer1 + protected + + OnCancel + + + + OnOK + + diff --git a/eeschema/dialogs/dialog_fields_editor_global_base.h b/eeschema/dialogs/dialog_fields_editor_global_base.h index 43d307e314..8b55a67e92 100644 --- a/eeschema/dialogs/dialog_fields_editor_global_base.h +++ b/eeschema/dialogs/dialog_fields_editor_global_base.h @@ -1,8 +1,8 @@ /////////////////////////////////////////////////////////////////////////// -// C++ code generated with wxFormBuilder (version Aug 4 2017) +// C++ code generated with wxFormBuilder (version Dec 30 2017) // http://www.wxformbuilder.org/ // -// PLEASE DO "NOT" EDIT THIS FILE! +// PLEASE DO *NOT* EDIT THIS FILE! /////////////////////////////////////////////////////////////////////////// #ifndef __DIALOG_FIELDS_EDITOR_GLOBAL_BASE_H__ @@ -11,8 +11,6 @@ #include #include #include -class DIALOG_SHIM; - #include "dialog_shim.h" #include #include @@ -20,11 +18,15 @@ class DIALOG_SHIM; #include #include #include +#include +#include +#include +#include #include #include -#include #include #include +#include #include #include @@ -44,39 +46,33 @@ class DIALOG_FIELDS_EDITOR_GLOBAL_BASE : public DIALOG_SHIM wxSplitterWindow* m_splitter1; wxPanel* m_leftPanel; wxCheckBox* m_groupComponentsBox; - wxButton* m_regroupComponentsButton; - wxDataViewListCtrl* m_columnListCtrl; + wxBitmapButton* m_bRefresh; + wxDataViewListCtrl* m_fieldsCtrl; wxPanel* m_panel4; - wxDataViewCtrl* m_bomView; - wxButton* m_applyChangesButton; - wxButton* m_revertChangesButton; - wxButton* m_closeButton; + wxGrid* m_grid; + wxStdDialogButtonSizer* m_sdbSizer1; + wxButton* m_sdbSizer1OK; + wxButton* m_sdbSizer1Cancel; // Virtual event handlers, overide them in your derived class - virtual void OnDialogClosed( wxCloseEvent& event ) { event.Skip(); } - virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); } virtual void OnGroupComponentsToggled( wxCommandEvent& event ) { event.Skip(); } virtual void OnRegroupComponents( wxCommandEvent& event ) { event.Skip(); } virtual void OnColumnItemToggled( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnBomColumReordered( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnBomColumnSorted( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnTableItemActivated( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnTableItemContextMenu( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnTableValueChanged( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnSelectionChanged( wxDataViewEvent& event ) { event.Skip(); } - virtual void OnApplyFieldChanges( wxCommandEvent& event ) { event.Skip(); } - virtual void OnRevertFieldChanges( wxCommandEvent& event ) { event.Skip(); } - virtual void OnCloseButton( wxCommandEvent& event ) { event.Skip(); } + virtual void OnSizeFieldList( wxSizeEvent& event ) { event.Skip(); } + virtual void OnTableValueChanged( wxGridEvent& event ) { event.Skip(); } + virtual void OnTableItemContextMenu( wxGridEvent& event ) { event.Skip(); } + virtual void OnCancel( wxCommandEvent& event ) { event.Skip(); } + virtual void OnOK( wxCommandEvent& event ) { event.Skip(); } public: - DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Fields editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); + DIALOG_FIELDS_EDITOR_GLOBAL_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Fields Editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); ~DIALOG_FIELDS_EDITOR_GLOBAL_BASE(); void m_splitter1OnIdle( wxIdleEvent& ) { - m_splitter1->SetSashPosition( 231 ); + m_splitter1->SetSashPosition( 200 ); m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL_BASE::m_splitter1OnIdle ), NULL, this ); } diff --git a/eeschema/fields_editor_table_column.cpp b/eeschema/fields_editor_table_column.cpp deleted file mode 100644 index 6c50e7deef..0000000000 --- a/eeschema/fields_editor_table_column.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -* This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Oliver Walters - * Copyright (C) 2017 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 2 - * 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, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "fields_editor_table_column.h" - -FIELDS_EDITOR_COLUMN_LIST::FIELDS_EDITOR_COLUMN_LIST() : m_nextFieldId( FIELDS_EDITOR_COL_ID_USER ) -{ - -} - -void FIELDS_EDITOR_COLUMN_LIST::Clear() -{ - Columns.clear(); - m_nextFieldId = FIELDS_EDITOR_COL_ID_USER; -} - -/** - * Return the number of columns - * @param aIncludeHidden - If this is false, only visible columns will be included - */ -unsigned int FIELDS_EDITOR_COLUMN_LIST::ColumnCount( bool aIncludeHidden ) const -{ - unsigned int count = 0; - - for( FIELDS_EDITOR_COLUMN* col : Columns ) - { - if( col && ( col->IsVisible() || aIncludeHidden ) ) - { - count++; - } - } - - return count; -} - -/** - * Return a column based on its stored position - */ -FIELDS_EDITOR_COLUMN* FIELDS_EDITOR_COLUMN_LIST::GetColumnByIndex( unsigned int aColId ) -{ - if( aColId < Columns.size() ) - return Columns[aColId]; - - return nullptr; -} - -/** - * Return a column based on its unique ID - */ -FIELDS_EDITOR_COLUMN* FIELDS_EDITOR_COLUMN_LIST::GetColumnById( unsigned int aColId ) -{ - for( unsigned int ii=0; iiId() == aColId ) - return Columns[ii]; - } - - return nullptr; -} - -/** - * Return a column based on its string title - */ -FIELDS_EDITOR_COLUMN* FIELDS_EDITOR_COLUMN_LIST::GetColumnByTitle( const wxString& aColTitle ) -{ - for( unsigned int ii=0; iiTitle().Cmp( aColTitle ) == 0 ) - return Columns[ii]; - } - - return nullptr; -} - -/** - * Test if the list includes a column with the given unique ID - */ -bool FIELDS_EDITOR_COLUMN_LIST::ContainsColumn( unsigned int aColId ) -{ - for( FIELDS_EDITOR_COLUMN* col : Columns ) - { - if( col && col->Id() == aColId ) - return true; - } - - return false; -} - -/** - * Test if the list includes a column with the given title - */ -bool FIELDS_EDITOR_COLUMN_LIST::ContainsColumn( const wxString& aColTitle ) -{ - return nullptr != GetColumnByTitle( aColTitle ); -} - -/** - * Add a new column to the list - */ -bool FIELDS_EDITOR_COLUMN_LIST::AddColumn( FIELDS_EDITOR_COLUMN* aCol ) -{ - if( nullptr == aCol ) - return false; - - if( ContainsColumn( aCol->Id() ) ) - return false; - - Columns.push_back( aCol ); - - // If this is a user field, increment the counter - if( aCol->Id() >= FIELDS_EDITOR_COL_ID_USER ) - m_nextFieldId++; - - return true; -} diff --git a/eeschema/fields_editor_table_column.h b/eeschema/fields_editor_table_column.h deleted file mode 100644 index 7ba996bab2..0000000000 --- a/eeschema/fields_editor_table_column.h +++ /dev/null @@ -1,152 +0,0 @@ -/* -* This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Oliver Walters - * Copyright (C) 2017 KiCad Developers, see CHANGELOG.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 2 - * 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, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef FIELDS_EDITOR_TABLE_COLUMN_H -#define FIELDS_EDITOR_TABLE_COLUMN_H - -#include -#include -#include - -// Default column names (translated) -#define FIELDS_EDITOR_COL_TITLE_REFERENCE _( "Reference" ) -#define FIELDS_EDITOR_COL_TITLE_DESCRIPTION _( "Description" ) -#define FIELDS_EDITOR_COL_TITLE_FOOTPRINT _( "Footprint" ) -#define FIELDS_EDITOR_COL_TITLE_VALUE _( "Value" ) -#define FIELDS_EDITOR_COL_TITLE_DATASHEET _( "Datasheet" ) -#define FIELDS_EDITOR_COL_TITLE_QUANTITY _( "Quantity" ) - -/** - * Column type enumeration - * Not currently implemented, - * in the future the different column 'types' might - * be used for something... - */ -enum FIELDS_EDITOR_COLUMN_TYPE -{ - FIELDS_EDITOR_COL_TYPE_KICAD = 0, ///< Default column (editable) - FIELDS_EDITOR_COL_TYPE_LIBRARY, ///< Default column (non-editable) - FIELDS_EDITOR_COL_TYPE_GENERATED, ///< Generated column (e.g. Quantity) - FIELDS_EDITOR_COL_TYPE_USER, ///< User data -}; - - -/** - * Predefined column ID values for default columns. - * User columns are assigned IDs of 1000 and above - */ -enum FIELDS_EDITOR_COLUMN_ID -{ - // Default component fields - FIELDS_EDITOR_COL_ID_REFERENCE = 0, - FIELDS_EDITOR_COL_ID_DESCRIPTION, - FIELDS_EDITOR_COL_ID_FOOTPRINT, - FIELDS_EDITOR_COL_ID_VALUE, - FIELDS_EDITOR_COL_ID_DATASHEET, - - // Meta-data fields - FIELDS_EDITOR_COL_ID_QUANTITY = 100, - - // Custom data fields - FIELDS_EDITOR_COL_ID_USER = 1000, -}; - -/** - * FIELDS_EDITOR_COLUMN class - * Models a single column in the BOM view - * Each column can be used to group components, - * and can be hidden from the output BOM - */ -class FIELDS_EDITOR_COLUMN -{ -protected: - unsigned int m_id; ///< Unique column ID - FIELDS_EDITOR_COLUMN_TYPE m_Type; ///< Column type - - wxString m_Title; ///< The column (field) title - bool m_Show; ///< Is this column visible? - bool m_ReadOnly; ///< Is this column read only? - - bool m_sort; ///< Is this column used for sorting? - -public: - FIELDS_EDITOR_COLUMN( unsigned int aId, FIELDS_EDITOR_COLUMN_TYPE aType, const wxString aTitle, bool aShow, bool aReadOnly = false, bool aSort = true ) : - m_id( aId ), - m_Type( aType ), - m_Title( aTitle.Strip( wxString::both ) ), - m_Show( aShow ), - m_ReadOnly( aReadOnly ), - m_sort( aSort ) - { - } - - unsigned int Id() const { return m_id; } - FIELDS_EDITOR_COLUMN_TYPE Type() const { return m_Type; } - wxString Title() const { return m_Title; } - bool IsVisible() const { return m_Show; } - bool IsReadOnly() const { return m_ReadOnly; } - bool IsUsedToSort() const { return m_sort; } - - //TODO - Should renaming of columns be allowed? - //bool SetTitle( const wxString aTitle ); - void SetVisible( bool aShow = true ) { m_Show = aShow; } - void SetReadOnly( bool aReadOnly = true ) { m_ReadOnly = aReadOnly; } - void SetUsedToSort( bool aSort = true ) { m_sort = aSort; } - -}; - -/* - * The FIELDS_EDITOR_COLUMN_LIST class contains information - * on all columns existing in the BOM - */ -class FIELDS_EDITOR_COLUMN_LIST -{ -protected: - - unsigned int m_nextFieldId; - -public: - std::vector< FIELDS_EDITOR_COLUMN* > Columns; - - FIELDS_EDITOR_COLUMN_LIST(); - - void Clear(); - - unsigned int NextFieldId() const { return m_nextFieldId; } - unsigned int ColumnCount( bool aIncludeHidden = true ) const; - - FIELDS_EDITOR_COLUMN* GetColumnByIndex( unsigned int aColIndex ); - FIELDS_EDITOR_COLUMN* GetColumnById( unsigned int aColId ); - FIELDS_EDITOR_COLUMN* GetColumnByTitle( const wxString& aColTitle ) ; - - bool ContainsColumn( unsigned int aColId ); - bool ContainsColumn( const wxString& aColTitle ); - - bool AddColumn( FIELDS_EDITOR_COLUMN* aCol ); - -}; - - - -#endif /* FIELDS_EDITOR_TABLE_COLUMN_H */ diff --git a/eeschema/fields_editor_table_model.cpp b/eeschema/fields_editor_table_model.cpp deleted file mode 100644 index 262ad49f95..0000000000 --- a/eeschema/fields_editor_table_model.cpp +++ /dev/null @@ -1,1615 +0,0 @@ -/* -* This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Oliver Walters - * Copyright (C) 2017 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 2 - * 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, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "fields_editor_table_model.h" - -// Indicator that multiple values exist in child rows -#define ROW_MULT_ITEMS wxString( "<...>" ) - -static const wxColor ROW_COLOUR_ITEM_CHANGED( 200, 0, 0 ); -static const wxColor ROW_COLOUR_MULTIPLE_ITEMS( 60, 90, 200 ); - - -/** - * Convert FIELDS_EDITOR_TABLE_ROW -> wxDataViewItem - */ -static wxDataViewItem RowToItem( FIELDS_EDITOR_TABLE_ROW const* aRow ) -{ - return wxDataViewItem( const_cast( static_cast( aRow ) ) ); -} - - -/** - * Convert wxDataViewItem -> FIELDS_EDITOR_TABEL_ROW - */ -static FIELDS_EDITOR_TABLE_ROW const* ItemToRow( wxDataViewItem aItem ) -{ - if( !aItem.IsOk() ) - { - return nullptr; - } - else - { - return static_cast( aItem.GetID() ); - } -} - - -FIELDS_EDITOR_FIELD_VALUES::FIELDS_EDITOR_FIELD_VALUES( const wxString& aRefDes, FIELD_VALUE_MAP* aTemplate ) : - m_refDes( aRefDes ), - m_templateValues( aTemplate ) -{ -} - - -bool FIELDS_EDITOR_FIELD_VALUES::GetFieldValue( unsigned int aFieldId, wxString& aValue ) const -{ - auto search = m_currentValues.find( aFieldId ); - - if( search == m_currentValues.end() ) - return false; - - aValue = search->second; - - return true; -} - - -bool FIELDS_EDITOR_FIELD_VALUES::GetBackupValue( unsigned int aFieldId, wxString& aValue ) const -{ - auto search = m_backupValues.find( aFieldId ); - - if( search == m_backupValues.end() ) - return false; - - aValue = search->second; - - return true; -} - - -bool FIELDS_EDITOR_FIELD_VALUES::GetTemplateValue( unsigned int aFieldId, wxString& aValue ) const -{ - if( !m_templateValues ) - return false; - - auto search = m_templateValues->find( aFieldId ); - - if( search == m_templateValues->end() ) - return false; - - aValue = search->second; - - return true; -} - - -void FIELDS_EDITOR_FIELD_VALUES::SetFieldValue( unsigned int aFieldId, const wxString& aValue, - bool aOverwrite ) -{ - if( aOverwrite || m_currentValues.count( aFieldId ) == 0 || - m_currentValues[aFieldId].IsEmpty() ) - { - m_currentValues[aFieldId] = aValue; - } -} - - -bool FIELDS_EDITOR_FIELD_VALUES::HasValueChanged( unsigned int aFieldId) const -{ - wxString currentValue, backupValue; - - GetFieldValue( aFieldId, currentValue ); - GetBackupValue( aFieldId, backupValue ); - - return currentValue.Cmp( backupValue ) != 0; -} - - -void FIELDS_EDITOR_FIELD_VALUES::RevertChanges( unsigned int aFieldId ) -{ - wxString backupValue; - - GetBackupValue( aFieldId, backupValue ); - - SetFieldValue( aFieldId, backupValue, true ); -} - -void FIELDS_EDITOR_FIELD_VALUES::SetBackupPoint() -{ - for( auto it = m_currentValues.begin(); it != m_currentValues.end(); ++it ) - { - m_backupValues[it->first] = it->second; - } -} - - -FIELDS_EDITOR_TABLE_ROW::FIELDS_EDITOR_TABLE_ROW() : m_columnList( nullptr ) -{ -} - - -/** - * Update cell attributes based on parameters of the cell - * Default implementation highlights cells that have been altered - */ -bool FIELDS_EDITOR_TABLE_ROW::GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const -{ - auto field = m_columnList->GetColumnById( aFieldId ); - - if( HasValueChanged( field ) ) - { - aAttr.SetBold( true ); - aAttr.SetItalic( true ); - aAttr.SetColour( ROW_COLOUR_ITEM_CHANGED ); - return true; - } - - return false; -} - - -bool FIELDS_EDITOR_TABLE_ROW::HasChanged() const -{ - if( !m_columnList ) - return false; - - for( auto& column : m_columnList->Columns ) - { - if( column && HasValueChanged( column ) ) - { - return true; - } - } - - return false; -} - - -/** - * Create a new group (which contains one or more components) - */ -FIELDS_EDITOR_TABLE_GROUP::FIELDS_EDITOR_TABLE_GROUP( FIELDS_EDITOR_COLUMN_LIST* aColumnList ) -{ - m_columnList = aColumnList; -} - - -bool FIELDS_EDITOR_TABLE_GROUP::GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const -{ - if( GetFieldValue( aFieldId ).Cmp( ROW_MULT_ITEMS ) == 0 ) - { - aAttr.SetItalic( true ); - aAttr.SetColour( ROW_COLOUR_MULTIPLE_ITEMS ); - return true; - } - - return FIELDS_EDITOR_TABLE_ROW::GetAttr( aFieldId, aAttr ); -} - - -/** - * Return the value associated with a given field in the group. - * Some fields require special attention. - */ -wxString FIELDS_EDITOR_TABLE_GROUP::GetFieldValue( unsigned int aFieldId ) const -{ - wxString value; - - // Account for special cases - switch( aFieldId ) - { - // QUANTITY returns the size of the group - case FIELDS_EDITOR_COL_ID_QUANTITY: - value = wxString::Format( "%u", (unsigned int) GroupSize() ); - break; - - // REFERENCE field returns consolidated list of references - case FIELDS_EDITOR_COL_ID_REFERENCE: - value = wxJoin( GetReferences(), ' ' ); - break; - - // Otherwise, return component data - default: - if( Components.size() == 0 ) - { - value = wxEmptyString; - } - else - { - // If the components in this group contain multiple items, - // display a special string indicating this - for( unsigned int i=0; iGetFieldValue( aFieldId ); - } - // Mismatch found - else if( value.Cmp( cmp->GetFieldValue( aFieldId ) ) != 0 ) - { - value = ROW_MULT_ITEMS; - break; - } - } - } - break; - } - - return value; -} - - -/** - * Set the value of a field in a group - * The new value is pushed to all components that are children of this group - */ -bool FIELDS_EDITOR_TABLE_GROUP::SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite ) -{ - bool result = false; - - for( auto& cmp : Components ) - { - result |= cmp->SetFieldValue( aFieldId, aValue, aOverwrite ); - } - - return result; -} - - -/** - * Determines if a given component matches against a particular field. - * - * - Tests each field in turn; all fields must match - * - Some fields require special checking - * - * @param aField - The field to test - * @param aComponent - The component being tested - */ -bool FIELDS_EDITOR_TABLE_GROUP::TestField( FIELDS_EDITOR_COLUMN* aField, FIELDS_EDITOR_TABLE_COMPONENT* aComponent ) const -{ - if( !aField || !aComponent ) - return false; - - if( Components.size() == 0 ) - return true; - - wxString componentValue; - wxString comparisonValue; - - // Some fields are handled in a special manner - // (handle these first) - switch( aField->Id() ) - { - // These fields should NOT be compared (return True) - case FIELDS_EDITOR_COL_ID_QUANTITY: - return true; - - // Reference matching is done only on prefix - case FIELDS_EDITOR_COL_ID_REFERENCE: - componentValue = aComponent->GetPrefix(); - comparisonValue = Components[0]->GetPrefix(); - break; - - default: - componentValue = aComponent->GetFieldValue( aField->Id() ); - comparisonValue = Components[0]->GetFieldValue( aField->Id() ); - break; - } - - bool result = componentValue.Cmp( comparisonValue ) == 0; - - return result; -} - - -/** - * Add a new component to the group. - * It is assumed at this stage that the component is a good match for the group. - * @param aComponent is the new component to add - */ -bool FIELDS_EDITOR_TABLE_GROUP::AddComponent( FIELDS_EDITOR_TABLE_COMPONENT* aComponent ) -{ - if( !aComponent ) - return false; - - // To be a match, all fields must match! - bool match = true; - - for( auto* column : m_columnList->Columns ) - { - // Ignore any columns marked as "not used for sorting" - if( !column->IsUsedToSort() ) - continue; - - match = TestField( column, aComponent ); - - // Escape on first mismatch - if( !match ) - { - break; - } - } - - if( match ) - { - aComponent->SetParent( this ); - Components.push_back( aComponent ); - return true; - } - else - { - return false; - } - - return false; -} - - -/** - * Adds each child row to the supplied list, and returns the total child count - */ -unsigned int FIELDS_EDITOR_TABLE_GROUP::GetChildren( wxDataViewItemArray& aChildren ) const -{ - // Show drop-down for child components - for( auto& row : Components ) - { - if( row ) - { - aChildren.push_back( RowToItem( &*row ) ); - } - } - - return aChildren.size(); -} - - -/** - * Test if any components in this group have a new value in the provided field - * @param aField is the field to test - * @return true if any children have changed else false - */ -bool FIELDS_EDITOR_TABLE_GROUP::HasValueChanged( FIELDS_EDITOR_COLUMN* aField ) const -{ - - bool changed = false; - - if( !aField ) - return false; - - for( auto const& row : Components ) - { - if( row->HasValueChanged( aField ) ) - { - changed = true; - break; - } - } - - // If the value has changed, the group field data must be updated - if( changed ) - { - //TODO - } - - return changed; -} - - -/** - * Return a list of (ordered) references - * for all the components in this group - * - * @param aSort - Sort the references - */ -wxArrayString FIELDS_EDITOR_TABLE_GROUP::GetReferences( bool aSort ) const -{ - wxArrayString refs; - - for( auto const& cmp : Components ) - { - if( cmp ) - { - refs.Add( cmp->GetFieldValue( FIELDS_EDITOR_COL_ID_REFERENCE ) ); - } - } - - if( aSort ) - { - refs.Sort( SortReferences ); - } - - return refs; -} - - -/** - * Compare two references (e.g. "R100", "R19") and perform a 'natural' sort - * This sorting must preserve numerical order rather than alphabetical - * e.g. "R100" is lower (alphabetically) than "R19" - * BUT should be placed after R19 - */ -int FIELDS_EDITOR_TABLE_GROUP::SortReferences( const wxString& aFirst, const wxString& aSecond ) -{ - // Default sorting - int defaultSort = aFirst.Cmp( aSecond ); - - static const wxString REGEX_STRING = "^([a-zA-Z]+)(\\d+)$"; - - // Compile regex statically - static wxRegEx regexFirst( REGEX_STRING, wxRE_ICASE | wxRE_ADVANCED ); - static wxRegEx regexSecond( REGEX_STRING, wxRE_ICASE | wxRE_ADVANCED ); - - if( !regexFirst.Matches( aFirst ) || !regexSecond.Matches( aSecond ) ) - { - return defaultSort; - } - - // First priority is to order by prefix - wxString prefixFirst = regexFirst.GetMatch( aFirst, 1 ); - wxString prefixSecond = regexSecond.GetMatch( aSecond, 1 ); - - if( prefixFirst.CmpNoCase( prefixSecond ) != 0 ) // Different prefixes! - { - return defaultSort; - } - - wxString numStrFirst = regexFirst.GetMatch( aFirst, 2 ); - wxString numStrSecond = regexSecond.GetMatch( aSecond, 2 ); - - // If either match failed, just return normal string comparison - if( numStrFirst.IsEmpty() || numStrSecond.IsEmpty() ) - { - return defaultSort; - } - - // Convert each number string to an integer - long numFirst = 0; - long numSecond = 0; - - // If either conversion fails, return normal string comparison - if( !numStrFirst.ToLong( &numFirst ) || !numStrSecond.ToLong( &numSecond ) ) - { - return defaultSort; - } - - return (int) (numFirst - numSecond); -} - - -/** - * Compare two VALUE fields. - * A value field can reasonably be expected to be one of: - * a) Purely numerical e.g. '22' - * b) Numerical with included units e.g. '15uF' - * c) Numerical with included prefix but no units e.g. '20n' - * d) Numerical with prefix inside number e.g. '4K7' - * e) Other, e.g. 'MAX232' - * - * Cases a) to d) should be detected and converted to a common representation - * Values that do not match this pattern should revert to standard string comparison - */ -int FIELDS_EDITOR_TABLE_GROUP::SortValues( const wxString& aFirst, const wxString& aSecond ) -{ - //TODO - Intelligent comparison of component values - // e.g. 4K > 499 - // e.g. 1nF < 0.1u - - // For now, just return default comparison - - return aFirst.CmpNoCase( aSecond ); -} - - -/** - * Create a new COMPONENT row - * Each COMPONENT row is associated with a single component item. - */ -FIELDS_EDITOR_TABLE_COMPONENT::FIELDS_EDITOR_TABLE_COMPONENT( FIELDS_EDITOR_TABLE_GROUP* aParent, - FIELDS_EDITOR_COLUMN_LIST* aColumnList, - FIELDS_EDITOR_FIELD_VALUES* aFieldValues ) -{ - m_parent = aParent; - m_columnList = aColumnList; - m_fieldValues = aFieldValues; -} - - -/** - * Try to add a unit to this component - * If the references match, it will be added - */ -bool FIELDS_EDITOR_TABLE_COMPONENT::AddUnit( const SCH_REFERENCE& aUnit ) -{ - // Addition is successful if the references match or there are currently no units in the group - if( Units.size() == 0 || Units[0].GetRef().Cmp( aUnit.GetRef() ) == 0 ) - { - Units.push_back( aUnit ); - - wxString value; - - // Extract the component data - for( auto column : m_columnList->Columns ) - { - auto cmp = aUnit.GetComp(); - - switch( column->Id() ) - { - case FIELDS_EDITOR_COL_ID_QUANTITY: - value = wxEmptyString; - break; - - case FIELDS_EDITOR_COL_ID_DESCRIPTION: - value = cmp->GetAliasDescription(); - break; - - case FIELDS_EDITOR_COL_ID_DATASHEET: - value = cmp->GetField( DATASHEET )->GetText(); - if( value.IsEmpty() ) - { - value = cmp->GetAliasDocumentation(); - } - break; - - case FIELDS_EDITOR_COL_ID_REFERENCE: - value = aUnit.GetRef(); - break; - - case FIELDS_EDITOR_COL_ID_VALUE: - value = cmp->GetField( VALUE )->GetText(); - break; - - case FIELDS_EDITOR_COL_ID_FOOTPRINT: - value = cmp->GetField( FOOTPRINT )->GetText(); - break; - - // User fields - default: - value = cmp->GetFieldText( column->Title(), false ); - break; - } - - m_fieldValues->SetFieldValue( column->Id(), value ); - } - - return true; - } - - return false; -} - - -/** - * Return the value associated with a particular field - * If no field is found, return an empty string - */ -wxString FIELDS_EDITOR_TABLE_COMPONENT::GetFieldValue( unsigned int aFieldId ) const -{ - wxString value; - - switch ( aFieldId ) - { - case FIELDS_EDITOR_COL_ID_QUANTITY: - return wxEmptyString; - - case FIELDS_EDITOR_COL_ID_REFERENCE: - return GetReference(); - - default: - break; - } - - if( m_fieldValues ) - { - m_fieldValues->GetFieldValue( aFieldId, value ); - - if( value.IsEmpty() ) - { - m_fieldValues->GetTemplateValue( aFieldId, value ); - } - } - - return value; -} - - -/** - * Set the value of a field in the component - * @param aFieldId is the unique ID of the field to update - * @param aValue is the new value - * @param aOverwrite enforces writing even if a value exists - */ -bool FIELDS_EDITOR_TABLE_COMPONENT::SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite ) -{ - if( m_fieldValues ) - { - m_fieldValues->SetFieldValue( aFieldId, aValue, aOverwrite ); - return true; - } - - return false; -} - - -wxString FIELDS_EDITOR_TABLE_COMPONENT::GetPrefix() const -{ - // Return the prefix of a component e.g. "R23" -> "R" - if( Units.size() == 0 ) - return wxEmptyString; - - return Units[0].GetComp()->GetPrefix(); -} - - -/** - * Return the reference of a component e.g. "R23" - */ -wxString FIELDS_EDITOR_TABLE_COMPONENT::GetReference() const -{ - if( Units.size() == 0 ) - return wxEmptyString; - - return Units[0].GetRef(); -} - - -/** - * Determines if the given field has been changed for this component - */ -bool FIELDS_EDITOR_TABLE_COMPONENT::HasValueChanged( FIELDS_EDITOR_COLUMN* aField ) const -{ - if( !aField ) - { - return false; - } - - return m_fieldValues->HasValueChanged( aField->Id() ); -} - - -/** - * If any changes have been made to this component, - * they are now applied to the schematic component - */ -void FIELDS_EDITOR_TABLE_COMPONENT::ApplyFieldChanges() -{ - for( auto& unit : Units ) - { - auto cmp = unit.GetComp(); - - if( !cmp ) - continue; - - // Iterate over each column - SCH_FIELD* field; - - for( auto& column : m_columnList->Columns ) - { - if( column && HasValueChanged( column ) ) - { - wxString value = GetFieldValue( column->Id() ); - - switch( column->Id() ) - { - // Ignore read-only fields - case FIELDS_EDITOR_COL_ID_REFERENCE: - case FIELDS_EDITOR_COL_ID_QUANTITY: - continue; - - // Special field considerations - case FIELDS_EDITOR_COL_ID_FOOTPRINT: - field = cmp->GetField( FOOTPRINT ); - break; - - case FIELDS_EDITOR_COL_ID_VALUE: - field = cmp->GetField( VALUE ); - break; - case FIELDS_EDITOR_COL_ID_DATASHEET: - field = cmp->GetField( DATASHEET ); - break; - - default: - // Find the field by name (but ignore default fields) - field = cmp->FindField( column->Title(), false ); - break; - } - - // New field needs to be added? - if( !field && !value.IsEmpty() ) - { - SCH_FIELD newField( wxPoint( 0, 0 ), -1, cmp, column->Title() ); - field = cmp->AddField( newField ); - } - - if( field ) - { - field->SetText( value ); - } - } - } - } -} - - -/** - * Revert the displayed fields for this component - * to their original values (matching the schematic data) - */ -void FIELDS_EDITOR_TABLE_COMPONENT::RevertFieldChanges() -{ - for( auto& column : m_columnList->Columns ) - { - switch( column->Id() ) - { - case FIELDS_EDITOR_COL_ID_REFERENCE: - case FIELDS_EDITOR_COL_ID_QUANTITY: - continue; - default: - break; - } - - m_fieldValues->RevertChanges( column->Id() ); - } -} - - -FIELDS_EDITOR_TABLE_MODEL::FIELDS_EDITOR_TABLE_MODEL() : - m_widget( nullptr ), - m_sortingColumn( FIELDS_EDITOR_COL_ID_REFERENCE ), - m_sortingOrder( true ) -{ - //TODO -} - - -/** - * Create a container for the FIELDS_EDITOR_TABLE_MODEL - * This is required for reference counting by wxDataViewCtrl - */ -FIELDS_EDITOR_TABLE_MODEL::MODEL_PTR FIELDS_EDITOR_TABLE_MODEL::Create() -{ - auto model = new FIELDS_EDITOR_TABLE_MODEL(); - - auto container = FIELDS_EDITOR_TABLE_MODEL::MODEL_PTR( model ); - - return container; -} - - -FIELDS_EDITOR_TABLE_MODEL::~FIELDS_EDITOR_TABLE_MODEL() -{ - //TODO -} - - -wxDataViewColumn* FIELDS_EDITOR_TABLE_MODEL::AddColumn( FIELDS_EDITOR_COLUMN* aColumn, int aPosition ) -{ - static const unsigned int flags = wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE; - - if( !m_widget || !aColumn || !aColumn->IsVisible() ) - return nullptr; - - wxDataViewCellMode editFlag = aColumn->IsReadOnly() ? wxDATAVIEW_CELL_INERT : wxDATAVIEW_CELL_EDITABLE; - - auto renderer = new wxDataViewTextRenderer( "string" , editFlag ); - - auto column = new wxDataViewColumn( aColumn->Title(), - renderer, - aColumn->Id(), - 150, //TODO - variable default width? - wxAlignment( wxALIGN_LEFT ), - flags ); - - // Work out where to insert the column - std::set columnsBefore; - - for( auto testCol : ColumnList.Columns ) - { - if( testCol->Id() == aColumn->Id() ) - { - break; - } - else - { - columnsBefore.insert( testCol->Id() ); - } - } - - bool found = false; - - for( unsigned int ii=0; iiGetColumnCount(); ii++ ) - { - auto col = m_widget->GetColumn( ii ); - - if( !col ) - continue; - - // If the new column is already in the view, escape - if( col->GetModelColumn() == aColumn->Id() ) - { - return col; - } - - // If we should insert the new column BEFORE this one - if( columnsBefore.count( col->GetModelColumn() ) == 0 ) - { - found = true; - m_widget->InsertColumn( ii, column ); - break; - } - } - - if( !found ) - m_widget->AppendColumn( column ); - - column->SetResizeable( true ); - - return column; -} - - -/** - * Gracefully remove the given column from the wxDataViewCtrl - * Removing columns individually prevents bad redraw of entire table - */ -bool FIELDS_EDITOR_TABLE_MODEL::RemoveColumn( FIELDS_EDITOR_COLUMN* aColumn ) -{ - if( !m_widget || !aColumn ) - return false; - - for( unsigned int ii=0; iiGetColumnCount(); ii++ ) - { - auto col = m_widget->GetColumn( ii ); - - if( col && col->GetModelColumn() == aColumn->Id() ) - { - m_widget->DeleteColumn( col ); - return true; - } - } - - return false; -} - - -/** - * Attach the MODEL to a particular VIEW - * This function causes the view to be updated appropriately - */ -void FIELDS_EDITOR_TABLE_MODEL::AttachTo( wxDataViewCtrl* aView ) -{ - if( !aView ) - { - return; - } - - m_widget = aView; - aView->Freeze(); - Cleared(); - - aView->AssociateModel( this ); - aView->ClearColumns(); - - // Add all columns - for( auto col : ColumnList.Columns ) - { - AddColumn( col ); - } - - aView->Thaw(); - - // Notify the view that the data needs to be redrawn - aView->Update(); -} - - -/** - * Return the total number of components displayed by the model - */ -unsigned int FIELDS_EDITOR_TABLE_MODEL::ComponentCount() const -{ - unsigned int count = 0; - - for( auto& group : Groups ) - { - if( group ) - count += group->GroupSize(); - } - - return count; -} - - -void FIELDS_EDITOR_TABLE_MODEL::ClearColumns() -{ - ColumnList.Clear(); -} - - -/** - * Add default columns to the table - * These columns are ALWAYS available in the table - * They are immutable - can be hidden by user but not removed - */ -void FIELDS_EDITOR_TABLE_MODEL::AddDefaultColumns() -{ - // Reference column is read-only - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_REFERENCE, - FIELDS_EDITOR_COL_TYPE_GENERATED, - FIELDS_EDITOR_COL_TITLE_REFERENCE, - true, true ) ); - - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_VALUE, - FIELDS_EDITOR_COL_TYPE_KICAD, - FIELDS_EDITOR_COL_TITLE_VALUE, - true, false ) ); - - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_FOOTPRINT, - FIELDS_EDITOR_COL_TYPE_KICAD, - FIELDS_EDITOR_COL_TITLE_FOOTPRINT, - true, false ) ); - - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_DATASHEET, - FIELDS_EDITOR_COL_TYPE_KICAD, - FIELDS_EDITOR_COL_TITLE_DATASHEET, - true, false ) ); - - // Description comes from .dcm file and is read-only - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_DESCRIPTION, - FIELDS_EDITOR_COL_TYPE_LIBRARY, - FIELDS_EDITOR_COL_TITLE_DESCRIPTION, - true, true ) ); - - // Quantity column is read-only - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( - FIELDS_EDITOR_COL_ID_QUANTITY, - FIELDS_EDITOR_COL_TYPE_GENERATED, - FIELDS_EDITOR_COL_TITLE_QUANTITY, - true, true ) ); -} - - -/** - * Extract field data from all components - * Compiles an inclusive list of all field names from all components - */ -void FIELDS_EDITOR_TABLE_MODEL::AddComponentFields( SCH_COMPONENT* aCmp ) -{ - std::vector< SCH_FIELD* > fields; - - SCH_FIELD* field; - wxString fieldName; - - if( nullptr == aCmp ) - return; - - // Extract custom columns from component - fields.clear(); - aCmp->GetFields( fields, false ); - - // Iterate over custom field datas - for( unsigned int i=MANDATORY_FIELDS; iGetName(); - - bool userMatchFound = false; - - // Search for the column within the existing columns - for( auto col : ColumnList.Columns ) - { - if( !col ) - { - continue; - } - - if( col->Title().Cmp( fieldName ) == 0 ) - { - if( col->Id() >= FIELDS_EDITOR_COL_ID_USER ) - { - userMatchFound = true; - break; - } - } - } - - // If a user-made column already exists with the same name, abort - if( userMatchFound ) - { - continue; - } - - ColumnList.AddColumn( new FIELDS_EDITOR_COLUMN( ColumnList.NextFieldId(), - FIELDS_EDITOR_COL_TYPE_USER, - field->GetName(), - true, false ) ); - } -} - - -/** - * Add a list of component items to the BOM manager - * Creates consolidated groups of components as required - */ -void FIELDS_EDITOR_TABLE_MODEL::SetComponents( SCH_REFERENCE_LIST aRefs, const TEMPLATE_FIELDNAMES& aTemplateFields ) -{ - - // Add default columns - AddDefaultColumns(); - - // Extract all component fields - for( unsigned int ii=0; iiId()] = field.m_Value; - } - - // Group multi-unit components together - m_components.clear(); - m_fieldValues.clear(); - - - // Iterate through each unique component - for( unsigned int ii=0; iiAddUnit( ref ) ) - { - found = true; - break; - } - } - - if( !found ) - { - // Find the field:value map associated with this component - wxString refDes = ref.GetComp()->GetField( REFERENCE )->GetText(); - - bool dataFound = false; - - FIELDS_EDITOR_FIELD_VALUES* values; - - for( auto& data : m_fieldValues ) - { - // Look for a match based on RefDes - if( data->GetReference().Cmp( refDes ) == 0 ) - { - dataFound = true; - values = &*data; - } - } - - if( !dataFound ) - { - values = new FIELDS_EDITOR_FIELD_VALUES( refDes, &m_fieldTemplates ); - m_fieldValues.push_back( std::unique_ptr( values ) ); - } - - auto* newComponent = new FIELDS_EDITOR_TABLE_COMPONENT( nullptr, &ColumnList, values ); - newComponent->AddUnit( ref ); - - m_components.push_back( std::unique_ptr( newComponent ) ); - } - } - - SetBackupPoint(); -} - - -void FIELDS_EDITOR_TABLE_MODEL::SetBackupPoint() -{ - // Mark backup locations for all values - for( auto& vals : m_fieldValues ) - { - vals->SetBackupPoint(); - } -} - - -/** - * Recalculate grouping of components and reload table - **/ -void FIELDS_EDITOR_TABLE_MODEL::ReloadTable() -{ - if( m_widget ) - { - m_widget->Freeze(); - } - - // Alert the view that the model data has changed - Cleared(); - - Groups.clear(); - - for( auto& cmp : m_components ) - { - bool grouped = false; - - if( m_groupColumns ) - { - for( auto& group : Groups ) - { - if( group->AddComponent( &*cmp ) ) - { - grouped = true; - break; - } - } - } - - // No suitable group was found for this component - if( !grouped ) - { - auto* newGroup = new FIELDS_EDITOR_TABLE_GROUP( &ColumnList ); - - newGroup->AddComponent( &*cmp ); - - Groups.push_back( std::unique_ptr( newGroup ) ); - } - } - - // Update the display - if( m_widget ) - { - //Cleared(); - m_widget->AssociateModel( this ); - m_widget->Thaw(); - } -} - - -/** - * Return a string array of data from a given row - */ -wxArrayString FIELDS_EDITOR_TABLE_MODEL::GetRowData( unsigned int aRow, std::vector aColumns ) const -{ - wxArrayString row; - - wxString data; - - if( Groups.size() <= aRow ) - return row; - - auto const& group = Groups[aRow]; - - if ( !group ) - return row; - - for( auto const col : aColumns ) - { - if( !col ) - { - row.Add( wxEmptyString ); - continue; - } - - row.Add( group->GetFieldValue( col->Id() ) ); - } - - return row; -} - - -/** - * Get the value of a particular item in the model - */ -void FIELDS_EDITOR_TABLE_MODEL::GetValue( wxVariant& aVariant, const wxDataViewItem& aItem, - unsigned int aFieldId ) const -{ - auto row = ItemToRow( aItem ); - - if( row ) - { - aVariant = row->GetFieldValue( aFieldId ); - } -} - - -/** - * Set the value of a particular item in the model - */ -bool FIELDS_EDITOR_TABLE_MODEL::SetValue( const wxVariant& aVariant, const wxDataViewItem& aItem, - unsigned int aFieldId ) -{ - if( !aItem.IsOk() || !m_widget ) - { - return false; - } - - // Extract the value to be set - if( aVariant.GetType().Cmp( "string" ) == 0 ) - { - wxString value = aVariant.GetString(); - - bool result = false; - - wxDataViewItemArray selectedItems; - m_widget->GetSelections( selectedItems ); - - // Set the row value for all selected rows - - for( auto item : selectedItems ) - { - auto selectedRow = static_cast( item.GetID() ); - - if( selectedRow ) - { - result |= selectedRow->SetFieldValue( aFieldId, value, true ); - } - } - - if( m_widget ) - { - m_widget->Update(); - } - - return result; - } - - // Default - return false; -} - - -/** - * Return the parent item for a given item in the model. - * If no parent is found (or the item is invalid) return an invalid item. - */ -wxDataViewItem FIELDS_EDITOR_TABLE_MODEL::GetParent( const wxDataViewItem& aItem ) const -{ - auto row = ItemToRow( aItem ); - auto parent = row ? row->GetParent() : nullptr; - - if( parent ) - { - return RowToItem( parent ); - } - - // Return an invalid item - return wxDataViewItem(); -} - - -/** - * Returns true if the supplied item has children - */ -bool FIELDS_EDITOR_TABLE_MODEL::IsContainer( const wxDataViewItem& aItem ) const -{ - auto row = ItemToRow( aItem ); - - if( row ) - { - return row->HasChildren(); - } - - return true; -} - - -/** - * Push all children of the supplied item into the list - * If the supplied item is invalid, push all the top-level items - */ -unsigned int FIELDS_EDITOR_TABLE_MODEL::GetChildren( const wxDataViewItem& aItem, - wxDataViewItemArray& aChildren ) const -{ - auto row = aItem.IsOk() ? ItemToRow( aItem ) : nullptr; - - // Valid row, return its children - if( row ) - { - return row->GetChildren( aChildren ); - } - else - { - for( auto& group : Groups ) - { - aChildren.Add( RowToItem( &*group ) ); - } - - return aChildren.size(); - } -} - - -bool FIELDS_EDITOR_TABLE_MODEL::GetAttr( const wxDataViewItem& aItem, - unsigned int aFieldId, - wxDataViewItemAttr& aAttr ) const -{ - auto row = aItem.IsOk() ? ItemToRow( aItem ) : nullptr; - - if( row ) - { - return row->GetAttr( aFieldId, aAttr ); - } - - return false; -} - - -/** - * Custom comparison function for improved column sorting - * Alphanumeric sorting is not sufficient for correct ordering of some fields - * Some columns are sorted numerically, others with more complex rules. - */ -int FIELDS_EDITOR_TABLE_MODEL::Compare( const wxDataViewItem& aItem1, - const wxDataViewItem& aItem2, - unsigned int aColumnId, - bool aAscending ) const -{ - if( !aItem1.IsOk() || !aItem2.IsOk() ) - return 0; - - int result = 0; - - auto row1 = ItemToRow( aItem1 ); - auto row2 = ItemToRow( aItem2 ); - - if( !row1 || !row2 ) - return 0; - - if( row1->GetParent() != row2->GetParent() ) - return 0; - - wxString strVal1 = row1->GetFieldValue( aColumnId ); - wxString strVal2 = row2->GetFieldValue( aColumnId ); - - long numVal1; - long numVal2; - - switch( aColumnId ) - { - // Reference column sorted by reference val - case FIELDS_EDITOR_COL_ID_REFERENCE: - result = FIELDS_EDITOR_TABLE_GROUP::SortReferences( strVal1, strVal2 ); - break; - - case FIELDS_EDITOR_COL_ID_VALUE: - result = FIELDS_EDITOR_TABLE_GROUP::SortValues( strVal1, strVal2 ); - break; - - // These columns are sorted numerically - case FIELDS_EDITOR_COL_ID_QUANTITY: - if( strVal1.ToLong( &numVal1 ) && strVal2.ToLong( &numVal2 ) ) - { - result = numVal1 - numVal2; - } - else - { - result = strVal1.Cmp( strVal2 ); - } - break; - - default: - // Default comparison (no special case) - result = strVal1.Cmp( strVal2 ); - break; - } - - // If initial sorting failed, sort secondly by reference - if( result == 0 && aColumnId != FIELDS_EDITOR_COL_ID_REFERENCE ) - { - result = FIELDS_EDITOR_TABLE_GROUP::SortReferences( - row1->GetFieldValue( FIELDS_EDITOR_COL_ID_REFERENCE ), - row2->GetFieldValue( FIELDS_EDITOR_COL_ID_REFERENCE ) ); - } - - // If sorting still failed, sort thirdly by value - if( result == 0 && aColumnId != FIELDS_EDITOR_COL_ID_VALUE ) - { - result = FIELDS_EDITOR_TABLE_GROUP::SortValues( - row1->GetFieldValue( FIELDS_EDITOR_COL_ID_VALUE ), - row2->GetFieldValue( FIELDS_EDITOR_COL_ID_VALUE ) ); - } - - if( !aAscending ) - { - result *= -1; - } - - return result; -} - - -/** - * Revert all component data back to the original values. - * The table view is updated accordingly - */ -void FIELDS_EDITOR_TABLE_MODEL::RevertFieldChanges() -{ - for( auto& group : Groups ) - { - if( !group ) - continue; - - bool changed = false; - - for( auto& component : group->Components ) - { - if( !component ) - continue; - - if( component->HasChanged() ) - { - component->RevertFieldChanges(); - ItemChanged( RowToItem( &*component ) ); - changed = true; - } - } - - // Update the group if any components changed - if( changed ) - { - ItemChanged( RowToItem( &*group ) ); - } - } -} - - -/** - * Apply all outstanding field changes. - * This is performed only when the window is closed - */ -void FIELDS_EDITOR_TABLE_MODEL::ApplyFieldChanges() -{ - for( auto& group : Groups ) - { - if( !group ) - continue; - - for( auto& component : group->Components ) - { - if( !component ) - continue; - - if( component->HasChanged() ) - { - component->ApplyFieldChanges(); - } - } - } -} - - -/** - * Tests if any component values in the table have been altered - */ -bool FIELDS_EDITOR_TABLE_MODEL::HaveFieldsChanged() const -{ - for( auto const& group : Groups ) - { - if( !group ) - continue; - - for( auto const& cmp : group->Components ) - { - if( !cmp ) - continue; - - if( cmp->HasChanged() ) - { - return true; - } - } - } - - return false; -} - - -/** - * Returns a list of only those components that have been changed - */ -std::vector FIELDS_EDITOR_TABLE_MODEL::GetChangedComponents() -{ - std::vector components; - - for( auto& group : Groups ) - { - if( !group ) - continue; - - for( auto& component : group->Components ) - { - if( !component ) - continue; - - if( component->HasChanged() ) - { - for( auto& unit : component->Units ) - { - components.push_back( unit ); - } - } - } - } - - return components; -} - - -/** - * Returns a count of the components that have been changed - */ -unsigned int FIELDS_EDITOR_TABLE_MODEL::CountChangedComponents() -{ - unsigned int count = 0; - - for( auto& group : Groups ) - { - if( !group ) - continue; - - for( auto& component : group->Components ) - { - if( component && component->HasChanged() ) - { - count++; - } - } - } - - return count; -} diff --git a/eeschema/fields_editor_table_model.h b/eeschema/fields_editor_table_model.h deleted file mode 100644 index b5aeb98f49..0000000000 --- a/eeschema/fields_editor_table_model.h +++ /dev/null @@ -1,362 +0,0 @@ -/* -* This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2017 Oliver Walters - * Copyright (C) 2017 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 2 - * 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, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef FIELDS_EDITOR_TABLE_MODEL_H -#define FIELDS_EDITOR_TABLE_MODEL_H - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "fields_editor_table_column.h" - -// Forward-declare classes -class FIELDS_EDITOR_TABLE_ROW; // Base-class for table row data model -class FIELDS_EDITOR_TABLE_GROUP; // Class for displaying a group of components -class FIELDS_EDITOR_TABLE_COMPONENT; // Class for displaying a single component - -// Map column IDs to field values (for quick lookup) -typedef std::map FIELD_VALUE_MAP; - - -/** - * The FIELDS_EDITOR_FIELD_VALUES class provides quick lookup of component values - * (based on Field ID) - * This is done for the following reasons: - * - Increase lookup speed for table values - * - Allow field values to be reverted to original values - * - Allow duplicate components to reference the same data - */ -class FIELDS_EDITOR_FIELD_VALUES -{ -public: - FIELDS_EDITOR_FIELD_VALUES( const wxString& aRefDes, FIELD_VALUE_MAP* aTemplate ); - - /** - * Return the current value for the provided field ID - * @return true if the field exists - * @param aFieldId = the field index - * @param aValue = a string to return the field value - */ - bool GetFieldValue( unsigned int aFieldId, wxString& aValue ) const; - - /** - * Return the backup value for the provided field ID - * @return true if the field exists - * @param aFieldId = the field index - * @param aValue = a string to return the field backup value - */ - bool GetBackupValue( unsigned int aFieldId, wxString& aValue ) const; - - /** - * Return the template value for a provided field ID (if it exists) - * @return true if the field exists - * @param aFieldId = the field index - * @param aValue = a string to return the field template value - */ - bool GetTemplateValue( unsigned int aFieldId, wxString& aValue ) const; - - /** - * Set the value for the provided field ID - * Field value is set under any of the following conditions: - * - param aOverwrite is true - * - There is no current value - * - The current value is empty - */ - void SetFieldValue( unsigned int aFieldId, const wxString& aValue, bool aOverwrite = false ); - - wxString GetReference() const { return m_refDes; } - - bool HasValueChanged( unsigned int aFieldId ) const; - - void RevertChanges( unsigned int aFieldId ); - - void SetBackupPoint(); - -protected: - //! The RefDes to which these values correspond - wxString m_refDes; - - //! Current values for each column - FIELD_VALUE_MAP m_currentValues; - - //! Backup values for each column - FIELD_VALUE_MAP m_backupValues; - - //! Template values for each column - FIELD_VALUE_MAP* m_templateValues; -}; - -/** - * Virtual base class determining how a row is displayed - * There are three types of rows: - * GROUP - Displays a group of (one or more) components - * COMPONENT - Displays a single component - * UNIT - Child of COMPONENT for multi-unit components - */ -class FIELDS_EDITOR_TABLE_ROW -{ -public: - FIELDS_EDITOR_TABLE_ROW(); - virtual ~FIELDS_EDITOR_TABLE_ROW() {} - - /// Set display properties for a cell - virtual bool GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const; - - /// Get the row value associated with provided field ID - virtual wxString GetFieldValue( unsigned int aFieldId ) const = 0; - - /// Set the field value associated with the provided field ID - virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) = 0; - - /// Return parent item - virtual FIELDS_EDITOR_TABLE_ROW* GetParent() const { return nullptr; } - - /// Test if row has any child rows - virtual bool HasChildren() const { return false; } - - /// Return any child rows - virtual unsigned int GetChildren( wxDataViewItemArray& aChildren ) const { return 0; } - - /// Determine if a value has changed - virtual bool HasValueChanged( FIELDS_EDITOR_COLUMN* aField ) const { return false; } - - /// Determine if any values have changed - bool HasChanged() const; - -protected: - - /// Pointer to list of columns - FIELDS_EDITOR_COLUMN_LIST* m_columnList; -}; - -/** - * FIELDS_EDITOR_TABLE_GROUP class displays a group of similar components - * If the group contains more than one component, - * they are each displayed as child items of the group - */ -class FIELDS_EDITOR_TABLE_GROUP : public FIELDS_EDITOR_TABLE_ROW -{ -public: - /// List of components stored in this group - std::vector Components; - - FIELDS_EDITOR_TABLE_GROUP( FIELDS_EDITOR_COLUMN_LIST* aColumnList ); - virtual ~FIELDS_EDITOR_TABLE_GROUP() {} - - /// Set display properties for a group row - virtual bool GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const override; - - /// Get group row value - virtual wxString GetFieldValue( unsigned int aFieldId ) const override; - - /// Set group row value - virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) override; - - /// Attempt to add a new component to the group - bool AddComponent( FIELDS_EDITOR_TABLE_COMPONENT* aComponent ); - - /// Test if this group should display children - virtual bool HasChildren() const override { return Components.size() > 1; } - - /// Return a list of children items of this group - virtual unsigned int GetChildren( wxDataViewItemArray& aChildren ) const override; - - /// Test if any children have changed - virtual bool HasValueChanged( FIELDS_EDITOR_COLUMN* aField ) const override; - - /// Return the number of child items in this group - unsigned int GroupSize( void ) const { return Components.size(); } - - /// Return a sorted, concatenated list of references - wxArrayString GetReferences( bool aSort = true ) const; - - /// Function for sorting two reference strings - static int SortReferences( const wxString& aFirst, const wxString& aSecond ); - - /// Function for sorting two value strings - static int SortValues( const wxString& aFirst, const wxString& aSecond ); - -protected: - /// Test if a particular field matches against another component - bool TestField( FIELDS_EDITOR_COLUMN* aField, FIELDS_EDITOR_TABLE_COMPONENT* aComponent ) const; -}; - -class FIELDS_EDITOR_TABLE_COMPONENT : public FIELDS_EDITOR_TABLE_ROW -{ -public: - // List of units associated with this component - std::vector Units; - - FIELDS_EDITOR_TABLE_COMPONENT( FIELDS_EDITOR_TABLE_GROUP* aParent, FIELDS_EDITOR_COLUMN_LIST* aColumnList, FIELDS_EDITOR_FIELD_VALUES* aValues ); - - bool AddUnit( const SCH_REFERENCE& aUnit ); - - virtual wxString GetFieldValue( unsigned int aFieldId ) const override; - - virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) override; - - virtual bool HasValueChanged( FIELDS_EDITOR_COLUMN* aField ) const override; - - /// Return the reference of the first unit (all units must be the same - wxString GetReference() const; - - /** - * @return the prefix of a component e.g. "R23" returns "R" - */ - wxString GetPrefix() const; - - void ApplyFieldChanges(); - - void RevertFieldChanges(); - - void SetParent( FIELDS_EDITOR_TABLE_GROUP* aParent ) { m_parent = aParent; } - - virtual FIELDS_EDITOR_TABLE_ROW* GetParent() const override { return m_parent; } - -protected: - FIELDS_EDITOR_TABLE_GROUP* m_parent; - - FIELDS_EDITOR_FIELD_VALUES* m_fieldValues; -}; - -/** - * FIELDS_EDITOR_TABLE_MODEL class - * - * Contains complete BOM information: - * a) List of columns (fields) to display - * b) List of groups of consolidated components - */ -class FIELDS_EDITOR_TABLE_MODEL : public wxDataViewModel -{ -protected: - FIELDS_EDITOR_TABLE_MODEL(); - - // Vector of unique component rows - std::vector> m_components; - - // Vector of field values mapped to field IDs - std::vector> m_fieldValues; - - // Template field values - FIELD_VALUE_MAP m_fieldTemplates; - - // BOM Preferences - //! Group components based on values - bool m_groupColumns = true; - //! Filter components - bool m_filterColumns = false; - //! Allow blank fields to be merged with otherwise matching groups - bool m_mergeBlankFields = false; - - wxDataViewCtrl* m_widget; - - //! ID of column to sort by - unsigned int m_sortingColumn; - bool m_sortingOrder; - - void AddDefaultColumns(); - void ClearColumns(); - - virtual bool HasContainerColumns( const wxDataViewItem& aItem ) const override { return true; } - - virtual bool IsContainer( const wxDataViewItem& aItem ) const override; - - virtual wxDataViewItem GetParent( const wxDataViewItem& aItem ) const override; - - virtual unsigned int GetChildren( const wxDataViewItem& aItem, wxDataViewItemArray& aChildren ) const override; - - virtual unsigned int GetColumnCount() const override { return ColumnList.ColumnCount( false ); } - - virtual wxString GetColumnType( unsigned int aFieldId ) const override { return wxString( "string" ); } - - virtual void GetValue( wxVariant& aVariant, const wxDataViewItem& aItem, unsigned int aFieldId ) const override; - - virtual bool SetValue( const wxVariant& aVariant, const wxDataViewItem& item, unsigned int aFieldId ) override; - -public: - - virtual ~FIELDS_EDITOR_TABLE_MODEL(); - - FIELDS_EDITOR_COLUMN_LIST ColumnList; - - /// List of component groups - std::vector> Groups; - - typedef wxObjectDataPtr MODEL_PTR; - - static MODEL_PTR Create(); - - void AttachTo( wxDataViewCtrl* aView ); - - wxDataViewColumn* AddColumn( FIELDS_EDITOR_COLUMN* aColumn, int aPosition = -1 ); - bool RemoveColumn( FIELDS_EDITOR_COLUMN* aColumn ); - - // wxDataViewModel functions - virtual bool GetAttr( const wxDataViewItem& aItem, unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const override; - virtual bool HasDefaultCompare() const override { return false; } - virtual int Compare( const wxDataViewItem& aItem1, - const wxDataViewItem& aItem2, - unsigned int aColumnId, - bool aAscending ) const override; - - void ReloadTable(); - - unsigned int ColumnCount() const { return ColumnList.ColumnCount(); } - unsigned int GroupCount() const { return (unsigned int) Groups.size(); } - unsigned int ComponentCount() const; - - void SetColumnGrouping( const bool aGroup = true ) { m_groupColumns = aGroup; } - bool GetColumnGrouping() const { return m_groupColumns; } - - void SetColumnFiltering( const bool aFilter = true ) { m_filterColumns = aFilter; } - bool GetColumnFiltering() const { return m_filterColumns; } - - void SetBlankMerging( const bool aMerge = true ) { m_mergeBlankFields = aMerge; } - bool GetBlankMerging() const { return m_mergeBlankFields; } - - wxArrayString GetRowData( unsigned int aRow, std::vector aColumns ) const; - - void SetComponents( SCH_REFERENCE_LIST aRefs, const TEMPLATE_FIELDNAMES& aTemplateFields ); - void AddComponentFields( SCH_COMPONENT* aCmp ); - - void RevertFieldChanges(); - void ApplyFieldChanges(); - - bool HaveFieldsChanged() const; - - void SetBackupPoint(); - - std::vector GetChangedComponents(); - unsigned int CountChangedComponents(); -}; - -#endif // FIELDS_EDITOR_TABLE_MODEL_H diff --git a/eeschema/sch_reference_list.h b/eeschema/sch_reference_list.h index 33953fc83d..1bb8582829 100644 --- a/eeschema/sch_reference_list.h +++ b/eeschema/sch_reference_list.h @@ -140,6 +140,19 @@ public: return m_Ref.c_str(); } + wxString GetRefNumber() const + { + wxString ref; + + // To avoid a risk of duplicate, for power components + // the ref number is 0nnn instead of nnn. + // Just because sometimes only power components are annotated + if( GetLibPart() && GetLibPart()->IsPower() ) + ref = wxT( "0" ); + + return ref << m_NumRef; + } + int CompareValue( const SCH_REFERENCE& item ) const { return m_Value->GetText().Cmp( item.m_Value->GetText() ); diff --git a/include/bitmaps.h b/include/bitmaps.h index a13292e40d..263dd15c16 100644 --- a/include/bitmaps.h +++ b/include/bitmaps.h @@ -441,6 +441,7 @@ EXTERN_BITMAP( read_setup_xpm ) EXTERN_BITMAP( recent_xpm ) EXTERN_BITMAP( redo_xpm ) EXTERN_BITMAP( red_xpm ) +EXTERN_BITMAP( refresh_xpm ) EXTERN_BITMAP( render_mode_xpm ) EXTERN_BITMAP( reload2_xpm ) EXTERN_BITMAP( reload_xpm ) diff --git a/include/kicad_string.h b/include/kicad_string.h index 3a4f45fbe9..f8ffe1a8e3 100644 --- a/include/kicad_string.h +++ b/include/kicad_string.h @@ -99,7 +99,7 @@ char* StrPurge( char* text ); wxString DateAndTime(); /** - * Function StrLenNumCmp + * Function StrNumCmp * is a routine compatible with qsort() to sort by alphabetical order. * * This function is equivalent to strncmp() or strncasecmp() if \a aIgnoreCase is true @@ -127,6 +127,16 @@ bool WildCompareString( const wxString& pattern, const wxString& string_to_tst, bool case_sensitive = true ); +/** + * Function ValueStringCompare + * acts just like the strcmp function but handles numbers and modifiers within the + * string text correctly for sorting. eg. 1mF > 55uF + * return -1 if first string is less than the second + * return 0 if the strings are equal + * return 1 if the first string is greater than the second + */ +int ValueStringCompare( const wxString& strFWord, const wxString& strSWord ); + /** * Function RefDesStringCompare * acts just like the strcmp function but treats numbers within the string text diff --git a/pcbnew/pcb_netlist.cpp b/pcbnew/pcb_netlist.cpp index cc4acc1ccf..137b7dd427 100644 --- a/pcbnew/pcb_netlist.cpp +++ b/pcbnew/pcb_netlist.cpp @@ -197,7 +197,7 @@ void NETLIST::SortByFPID() */ bool operator < ( const COMPONENT& item1, const COMPONENT& item2 ) { - return StrNumCmp( item1.GetReference(), item2.GetReference(), INT_MAX, true ) < 0; + return RefDesStringCompare(item1.GetReference(), item2.GetReference() ) < 0; }