22#include <wx/settings.h>
40 bool aAddedByUser,
bool aIsCheckbox )
46 m_cols.push_back( { aFieldName, aLabel, aAddedByUser,
false,
false, aIsCheckbox } );
54 const wxString& aFieldName )
75 else if( aFieldName == wxS(
"Keywords" ) )
104 const wxString fieldName =
m_cols[aCol].m_fieldName;
108 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
109 auto it = fieldStore.find( fieldName );
111 if( it != fieldStore.end() )
113 it->second.m_currentData = wxEmptyString;
114 it->second.m_currentlyEmpty =
true;
115 it->second.m_isModified =
true;
116 fieldStore.erase( it );
130 std::map<int, wxGridCellAttr*> newColAttrs;
135 newColAttrs[col - 1] = attr;
137 newColAttrs[col] = attr;
142 if( wxGrid*
grid = GetView() )
144 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_COLS_DELETED, aCol, 1 );
145 grid->ProcessTableMessage( msg );
157 if(
auto node =
m_dataStore[symbol->m_Uuid].extract(
m_cols[aCol].m_fieldName ) )
159 node.key() = newName;
160 node.mapped().m_isModified =
true;
161 m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
165 m_cols[aCol].m_fieldName = newName;
166 m_cols[aCol].m_label = newName;
173 for(
size_t i = 0; i <
m_cols.size(); i++ )
185 size_t foundCount = 0;
187 if( aNewOrder.size() >
m_cols.size() )
188 wxLogDebug(
"New order contains more fields than existing columns." );
190 for(
const wxString& newField : aNewOrder )
193 for(
size_t i = 0; i <
m_cols.size() && foundCount <
m_cols.size(); i++ )
195 if(
m_cols[i].m_fieldName == newField )
205 wxLogDebug(
"Field '%s' not found in existing columns.", newField );
208 if( foundCount !=
m_cols.size() && foundCount != aNewOrder.size() )
210 wxLogDebug(
"Not all fields in the new order were found in the existing columns." );
218 for(
int col = 0; col < aCol; ++col )
237 std::set<wxString> mixedValues;
240 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(), fieldValue );
253 if( listMixedValues )
254 mixedValues.insert( refFieldValue );
255 else if( ref ==
group.m_Refs.front() )
256 fieldValue = refFieldValue;
257 else if( fieldValue != refFieldValue )
261 if( listMixedValues )
263 fieldValue = wxEmptyString;
265 for(
const wxString& value : mixedValues )
267 if( value.IsEmpty() )
269 else if( fieldValue.IsEmpty() )
272 fieldValue +=
"," + value;
282 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
303 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
310 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
311 return m_cols[aCol].m_isCheckbox;
317 wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
325 wxGridCellAttr* newAttr =
m_colAttrs[aCol]->Clone();
328 if( attr->HasBackgroundColour() && !newAttr->HasBackgroundColour() )
329 newAttr->SetBackgroundColour( attr->GetBackgroundColour() );
330 if( attr->HasTextColour() && !newAttr->HasTextColour() )
331 newAttr->SetTextColour( attr->GetTextColour() );
332 if( attr->HasFont() && !newAttr->HasFont() )
333 newAttr->SetFont( attr->GetFont() );
345 attr =
new wxGridCellAttr;
348 bool rowModified =
false;
349 bool cellModified =
false;
350 bool cellEmpty =
true;
351 bool blankModified =
false;
353 const wxString& fieldName =
m_cols[aCol].m_fieldName;
369 blankModified =
true;
375 if(
m_dataStore[ref->m_Uuid][col.m_fieldName].m_isModified )
383 if( cellModified && rowModified && !cellEmpty )
392 if( stripedRenderer )
394 attr->SetRenderer( stripedRenderer );
395 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
399 if(
m_dataStore[ref->m_Uuid][fieldName].m_isModified )
401 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
true;
403 if(
m_dataStore[ref->m_Uuid][fieldName].m_currentlyEmpty )
405 if(
m_dataStore[ref->m_Uuid][fieldName].m_originallyEmpty )
407 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
409 else if(
m_dataStore[ref->m_Uuid][fieldName].m_originalData.empty() )
411 attr->SetBackgroundColour( wxColour( 180, 220, 180 ) );
415 attr->SetBackgroundColour( wxColour( 220, 180, 180 ) );
418 else if(
m_dataStore[ref->m_Uuid][fieldName].m_currentData.IsEmpty() )
420 attr->SetBackgroundColour( wxColour( 180, 200, 180 ) );
424 attr->SetBackgroundColour( wxColour( 200, 180, 180 ) );
432 bool wasStriped =
false;
436 if(
m_dataStore[ref->m_Uuid][fieldName].m_isStriped )
439 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
false;
445 attr =
new wxGridCellAttr;
448 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
451 attr->SetBackgroundColour( wxColour( 192, 255, 192 ) );
458 if( attr->HasFont() )
459 font = attr->GetFont();
461 font = GetView()->GetDefaultCellFont();
468 attr->SetFont( font );
478 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
479 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
482 const wxString& fieldName =
m_cols[aCol].m_fieldName;
484 std::map<wxString, LIB_DATA_ELEMENT>& parentFieldStore =
m_dataStore[parentSymbol->
m_Uuid];
487 wxString derivedSymbolFieldName =
"__DERIVED_SYMBOL_" + fieldName +
"__";
497 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Parent symbol name='%s', UUID='%s'",
499 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Stored creation request for symbol '%s' under parent UUID %s, special field '%s'",
500 aNewSymbolName, parentSymbol->
m_Uuid.
AsString(), derivedSymbolFieldName );
507 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
508 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
512 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
513 aNewSymbolName, parentSymbol->
GetName() );
516 KIID newDerivedSymbolUuid;
529 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
536 if( sym->m_Uuid == aNewSymbolUuid )
546 newSymbol->
SetName( aNewSymbolName );
553 const_cast<KIID&
>( newSymbol->
m_Uuid ) = aNewSymbolUuid;
556 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Added new symbol to list, size now: %zu",
560 for(
const auto& col :
m_cols )
565 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Initialized field data for new symbol" );
572 wxLogTrace(
traceLibFieldTable,
"Created derived symbol '%s' for library '%s', total tracked: %zu",
584 for(
auto& [
name, element] : fieldStore )
586 element.m_currentData = element.m_originalData;
587 element.m_isModified =
false;
588 element.m_currentlyEmpty =
false;
594 for(
const auto& [symId, fieldStore] :
m_dataStore )
596 for(
const auto& [
name, element] : fieldStore )
598 if( element.m_isModified )
610 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
617 if(
m_cols[aCol].m_fieldName == wxS(
"Keywords" ) )
642 if( lhGroup.
m_Refs.size() == 0 )
644 else if( rhGroup.
m_Refs.size() == 0 )
650 [ ascending ](
const wxString& a,
const wxString& b )
659 wxString lhs = dataModel->
GetValue( lhGroup, sortCol ).Trim(
true ).Trim(
false );
660 wxString rhs = dataModel->
GetValue( rhGroup, sortCol ).Trim(
true ).Trim(
false );
662 if( lhs == rhs && lhGroup.
m_Refs.size() > 1 && rhGroup.
m_Refs.size() > 1 )
664 wxString lhRef = lhGroup.
m_Refs[1]->GetName();
665 wxString rhRef = rhGroup.
m_Refs[1]->GetName();
666 return local_cmp( lhRef, rhRef );
670 return local_cmp( lhs, rhs );
683 std::sort( row.m_Refs.begin(), row.m_Refs.end(),
686 wxString lhs_ref( lhs->GetRef( nullptr ) );
687 wxString rhs_ref( rhs->GetRef( nullptr ) );
688 return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
695 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
703 row.m_ItemNumber = itemNumber++;
713 bool matchFound =
false;
718 for(
size_t i = 0; i <
m_cols.size(); ++i )
736 const wxString& aAttributeName )
738 if( aAttributeName == wxS(
"${DNP}" ) )
739 return aSymbol->
GetDNP() ? wxS(
"1" ) : wxS(
"0" );
741 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
744 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
747 if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
750 if( aAttributeName == wxS(
"Power" ) )
751 return aSymbol->
IsPower() ? wxS(
"1" ) : wxS(
"0" );
753 if( aAttributeName == wxS(
"LocalPower" ) )
754 return aSymbol->
IsLocalPower() ? wxS(
"1" ) : wxS(
"0" );
761 const wxString& aAttributeName,
762 const wxString& aValue )
764 if( aAttributeName == wxS(
"${DNP}" ) )
765 aSymbol->
SetDNP( aValue == wxS(
"1" ) );
766 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
768 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
770 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
772 else if( aAttributeName == wxS(
"LocalPower" ) )
775 if( aValue == wxS(
"0" ) )
780 else if( aAttributeName == wxS(
"Power" ) )
782 if( aValue == wxS(
"0" ) )
788 wxLogDebug(
"Unknown attribute name: %s", aAttributeName );
800 static_cast<WX_GRID*
>( GetView() )->CommitPendingChanges(
true );
802 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (
int)
m_rows.size() );
803 GetView()->ProcessTableMessage( msg );
813 ref->GetName(), ref->m_Uuid.AsString() );
819 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[ref->m_Uuid];
823 auto it = fieldStore.find( col.m_fieldName );
836 bool matchFound =
false;
854 row.m_Refs.push_back( ref );
866 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (
int)
m_rows.size() );
867 GetView()->ProcessTableMessage( msg );
877 std::vector<LIB_DATA_MODEL_ROW> children;
881 bool matchFound =
false;
887 if( children.size() < 2 )
890 std::sort( children.begin(), children.end(),
893 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
897 m_rows.insert(
m_rows.begin() + aRow + 1, children.begin(), children.end() );
899 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, (
int) children.size() );
900 GetView()->ProcessTableMessage( msg );
906 auto firstChild =
m_rows.begin() + aRow + 1;
907 auto afterLastChild = firstChild;
910 while( afterLastChild !=
m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
917 m_rows.erase( firstChild, afterLastChild );
919 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
920 GetView()->ProcessTableMessage( msg );
937 for(
size_t i = 0; i <
m_rows.size(); ++i )
950 for(
size_t i = 0; i <
m_rows.size(); ++i )
959 std::function<
void()> postApplyHandler )
963 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
965 for(
auto& srcData : fieldStore )
967 const wxString& srcName = srcData.first;
973 symbolChangeHandler( symbol );
991 if( srcName.StartsWith(
"__DERIVED_SYMBOL_" ) && srcName.EndsWith(
"__" ) )
994 if( srcName == wxS(
"Keywords" ) )
996 symbol->SetKeyWords( srcValue );
1004 SCH_FIELD* destField = symbol->GetField( srcName );
1006 bool userAdded = ( col != -1 &&
m_cols[col].m_userAdded );
1009 bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
1013 const VECTOR2I symbolPos = symbol->GetPosition();
1016 symbol->AddField( destField );
1029 if( !srcValue.IsEmpty() )
1038 destField->
SetText( srcValue );
1047 std::vector<SCH_FIELD*> symbolFields;
1048 symbol->GetFields( symbolFields );
1053 if( field->IsMandatory() )
1056 const wxString& existingName = field->GetName();
1058 bool stillTracked = std::any_of( fieldStore.begin(), fieldStore.end(),
1059 [&](
const auto&
kv )
1061 return kv.first == existingName;
1066 symbolChangeHandler( symbol );
1067 symbol->RemoveField( field );
1075 for(
auto& [fieldName, element] : fieldStore )
1077 if( element.m_createDerivedSymbol )
1084 KIID parentUuid( element.m_originalData );
1088 if( sym->m_Uuid == parentUuid )
1105 if( sym->GetName() == element.m_originalData )
1115 wxString actualDerivedName = element.m_derivedSymbolName;
1118 if( actualDerivedName == parentSymbol->
GetName() )
1121 actualDerivedName = parentSymbol->
GetName() +
"_1";
1125 bool nameExists =
true;
1127 while( nameExists && variant < 100 )
1133 if( sym->GetName() == actualDerivedName )
1142 actualDerivedName = parentSymbol->
GetName() +
"_" + wxString::Format(
"%d", variant );
1149 KIID newDerivedSymbolUuid;
1154 element.m_createDerivedSymbol =
false;
1163 if( postApplyHandler )
1187 return wxGRID_VALUE_BOOL;
1189 return wxGridTableBase::GetTypeName( row, col );
1195 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(),
nullptr );
1197 const wxString& fieldName =
m_cols[aCol].m_fieldName;
1203 it->second->IncRef();
1207 wxGridCellRenderer* stripedRenderer =
nullptr;
1212 stripedRenderer->IncRef();
1216 stripedRenderer->IncRef();
1217 return stripedRenderer;
1224 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(),
false );
wxString AsString() const
void SetFieldsOrder(const std::vector< wxString > &aNewOrder)
wxGridCellRenderer * getStripedRenderer(int aCol) const
void SetValue(int aRow, int aCol, const wxString &aValue) override
wxString GetColFieldName(int aCol)
wxString getAttributeValue(const LIB_SYMBOL *, const wxString &aAttributeName)
std::vector< std::pair< LIB_SYMBOL *, wxString > > m_createdDerivedSymbols
static bool cmp(const LIB_DATA_MODEL_ROW &lhGroup, const LIB_DATA_MODEL_ROW &rhGroup, LIB_FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
std::map< KIID, std::map< wxString, LIB_DATA_ELEMENT > > m_dataStore
static const wxString ITEM_NUMBER_VARIABLE
std::map< wxString, wxGridCellRenderer * > m_stripedRenderers
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) override
static const wxString SYMBOL_NAME
void CreateDerivedSymbolImmediate(int aRow, int aCol, wxString &aNewSymbolName)
bool isStripeableField(int aCol)
wxString GetValue(int aRow, int aCol) override
void RemoveColumn(int aCol)
bool ColIsCheck(int aCol)
void createActualDerivedSymbol(const LIB_SYMBOL *aParentSymbol, const wxString &aNewSymbolName, const KIID &aNewSymbolUuid)
std::vector< LIB_DATA_MODEL_COL > m_cols
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser, bool aIsCheckbox)
void ApplyData(std::function< void(LIB_SYMBOL *)> symbolChangeHandler, std::function< void()> postApplyHandler=nullptr)
void ExpandCollapseRow(int aRow)
std::vector< LIB_DATA_MODEL_ROW > m_rows
int GetFieldNameCol(const wxString &aFieldName)
void updateDataStoreSymbolField(const LIB_SYMBOL *aSymbol, const wxString &aFieldName)
void RenameColumn(int aCol, const wxString &newName)
std::vector< LIB_SYMBOL * > m_symbolsList
bool groupMatch(const LIB_SYMBOL *lhRef, const LIB_SYMBOL *rhRef)
int GetDataWidth(int aCol)
void CreateDerivedSymbol(int aRow, int aCol, wxString &aNewSymbolName)
void ClearCell(int aRow, int aCol)
void setAttributeValue(LIB_SYMBOL *aSymbol, const wxString &aAttributeName, const wxString &aValue)
void CollapseRow(int aRow)
wxString GetTypeName(int row, int col) override
LIB_FIELDS_EDITOR_GRID_DATA_MODEL()
bool IsExpanderColumn(int aCol) const override
bool ColIsSymbolName(int aCol)
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Define a library symbol object.
const LIB_ID & GetLibId() const override
wxString GetKeyWords() const override
bool IsPower() const override
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
void SetParent(LIB_SYMBOL *aParent=nullptr)
wxString GetName() const override
SCH_FIELD & GetValueField()
Return reference to the value field.
bool IsLocalPower() const override
virtual void SetName(const wxString &aName)
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
virtual bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
virtual void SetDNP(bool aDNP, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
virtual bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
std::map< int, wxGridCellAttr * > m_colAttrs
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
STRIPED_CELL_RENDERER< wxGridCellStringRenderer > STRIPED_STRING_RENDERER
const wxChar *const traceLibFieldTable
KICOMMON_API wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
bool m_createDerivedSymbol
wxString m_derivedSymbolName
std::vector< const LIB_SYMBOL * > m_Refs
bool FieldNamesAreDuplicates(const wxString &aLhs, const wxString &aRhs, std::initializer_list< FIELD_T > aMandatoryFields)
Test whether two field names should be treated as duplicates for the purposes of field name uniquenes...
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxLogTrace helper definitions.
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
VECTOR2< int32_t > VECTOR2I
GROUP_COLLAPSED_DURING_SORT