From 000457db7cbf59d4d8052d936465ad473e4af2fa Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Tue, 17 Apr 2018 11:34:48 +0100 Subject: [PATCH] Move Fields Editor to wxGrid. Makes in-place editing much easier and fixes some other issues (see bug reports). Fixed sorting bugs in References and added better sorting for Values. Removed Description column as it wasn't editable and caused more confusion than value. Removed auto-column-width after initial render. Re-implemented undo/redo. Fixes: lp:1749287 * https://bugs.launchpad.net/kicad/+bug/1749287 Fixes: lp:1737361 * https://bugs.launchpad.net/kicad/+bug/1737361 Fixes: lp:1759756 * https://bugs.launchpad.net/kicad/+bug/1759756 Fixes: lp:1763223 * https://bugs.launchpad.net/kicad/+bug/1763223 Fixes: lp:1761378 * https://bugs.launchpad.net/kicad/+bug/1761378 --- bitmaps_png/CMakeLists.txt | 1 + bitmaps_png/cpp_16/refresh.cpp | 39 + bitmaps_png/sources/refresh.svg | 7 + common/string.cpp | 145 +- eeschema/CMakeLists.txt | 2 - eeschema/component_references_lister.cpp | 8 +- .../dialogs/dialog_fields_editor_global.cpp | 744 ++++---- .../dialogs/dialog_fields_editor_global.h | 65 +- .../dialog_fields_editor_global_base.cpp | 133 +- .../dialog_fields_editor_global_base.fbp | 614 +++---- .../dialog_fields_editor_global_base.h | 44 +- eeschema/fields_editor_table_column.cpp | 136 -- eeschema/fields_editor_table_column.h | 152 -- eeschema/fields_editor_table_model.cpp | 1615 ----------------- eeschema/fields_editor_table_model.h | 362 ---- eeschema/sch_reference_list.h | 13 + include/bitmaps.h | 1 + include/kicad_string.h | 12 +- pcbnew/pcb_netlist.cpp | 2 +- 19 files changed, 937 insertions(+), 3158 deletions(-) create mode 100644 bitmaps_png/cpp_16/refresh.cpp create mode 100644 bitmaps_png/sources/refresh.svg delete mode 100644 eeschema/fields_editor_table_column.cpp delete mode 100644 eeschema/fields_editor_table_column.h delete mode 100644 eeschema/fields_editor_table_model.cpp delete mode 100644 eeschema/fields_editor_table_model.h 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; }