22#include <wx/settings.h>
39 bool aAddedByUser,
bool aIsCheckbox )
45 m_cols.push_back( { aFieldName, aLabel, aAddedByUser,
false,
false, aIsCheckbox } );
53 const wxString& aFieldName )
74 else if( aFieldName == wxS(
"Keywords" ) )
103 const wxString fieldName =
m_cols[aCol].m_fieldName;
107 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
108 auto it = fieldStore.find( fieldName );
110 if( it != fieldStore.end() )
112 it->second.m_currentData = wxEmptyString;
113 it->second.m_currentlyEmpty =
true;
114 it->second.m_isModified =
true;
115 fieldStore.erase( it );
129 if(
auto node =
m_dataStore[symbol->m_Uuid].extract(
m_cols[aCol].m_fieldName ) )
131 node.key() = newName;
132 node.mapped().m_isModified =
true;
133 m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
137 m_cols[aCol].m_fieldName = newName;
138 m_cols[aCol].m_label = newName;
145 for(
size_t i = 0; i <
m_cols.size(); i++ )
147 if(
m_cols[i].m_fieldName == aFieldName )
157 size_t foundCount = 0;
159 if( aNewOrder.size() >
m_cols.size() )
160 wxLogDebug(
"New order contains more fields than existing columns." );
162 for(
const wxString& newField : aNewOrder )
165 for(
size_t i = 0; i <
m_cols.size() && foundCount <
m_cols.size(); i++ )
167 if(
m_cols[i].m_fieldName == newField )
177 wxLogDebug(
"Field '%s' not found in existing columns.", newField );
180 if( foundCount !=
m_cols.size() && foundCount != aNewOrder.size() )
182 wxLogDebug(
"Not all fields in the new order were found in the existing columns." );
190 for(
int col = 0; col < aCol; ++col )
209 std::set<wxString> mixedValues;
212 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(), fieldValue );
225 if( listMixedValues )
226 mixedValues.insert( refFieldValue );
227 else if( ref ==
group.m_Refs.front() )
228 fieldValue = refFieldValue;
229 else if( fieldValue != refFieldValue )
233 if( listMixedValues )
235 fieldValue = wxEmptyString;
237 for(
const wxString& value : mixedValues )
239 if( value.IsEmpty() )
241 else if( fieldValue.IsEmpty() )
244 fieldValue +=
"," + value;
254 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
275 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
282 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
283 return m_cols[aCol].m_isCheckbox;
289 wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
297 wxGridCellAttr* newAttr =
m_colAttrs[aCol]->Clone();
300 if( attr->HasBackgroundColour() && !newAttr->HasBackgroundColour() )
301 newAttr->SetBackgroundColour( attr->GetBackgroundColour() );
302 if( attr->HasTextColour() && !newAttr->HasTextColour() )
303 newAttr->SetTextColour( attr->GetTextColour() );
304 if( attr->HasFont() && !newAttr->HasFont() )
305 newAttr->SetFont( attr->GetFont() );
317 attr =
new wxGridCellAttr;
320 bool rowModified =
false;
321 bool cellModified =
false;
322 bool cellEmpty =
true;
323 bool blankModified =
false;
325 const wxString& fieldName =
m_cols[aCol].m_fieldName;
341 blankModified =
true;
347 if(
m_dataStore[ref->m_Uuid][col.m_fieldName].m_isModified )
355 if( cellModified && rowModified && !cellEmpty )
364 if( stripedRenderer )
366 attr->SetRenderer( stripedRenderer );
367 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
371 if(
m_dataStore[ref->m_Uuid][fieldName].m_isModified )
373 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
true;
375 if(
m_dataStore[ref->m_Uuid][fieldName].m_currentlyEmpty )
377 if(
m_dataStore[ref->m_Uuid][fieldName].m_originallyEmpty )
379 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
381 else if(
m_dataStore[ref->m_Uuid][fieldName].m_originalData.empty() )
383 attr->SetBackgroundColour( wxColour( 180, 220, 180 ) );
387 attr->SetBackgroundColour( wxColour( 220, 180, 180 ) );
390 else if(
m_dataStore[ref->m_Uuid][fieldName].m_currentData.IsEmpty() )
392 attr->SetBackgroundColour( wxColour( 180, 200, 180 ) );
396 attr->SetBackgroundColour( wxColour( 200, 180, 180 ) );
404 bool wasStriped =
false;
408 if(
m_dataStore[ref->m_Uuid][fieldName].m_isStriped )
411 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
false;
417 attr =
new wxGridCellAttr;
420 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
423 attr->SetBackgroundColour( wxColour( 192, 255, 192 ) );
430 if( attr->HasFont() )
431 font = attr->GetFont();
433 font = GetView()->GetDefaultCellFont();
440 attr->SetFont( font );
450 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
451 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
454 const wxString& fieldName =
m_cols[aCol].m_fieldName;
456 std::map<wxString, LIB_DATA_ELEMENT>& parentFieldStore =
m_dataStore[parentSymbol->
m_Uuid];
459 wxString derivedSymbolFieldName =
"__DERIVED_SYMBOL_" + fieldName +
"__";
469 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Parent symbol name='%s', UUID='%s'",
471 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Stored creation request for symbol '%s' under parent UUID %s, special field '%s'",
472 aNewSymbolName, parentSymbol->
m_Uuid.
AsString(), derivedSymbolFieldName );
479 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
480 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
484 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
485 aNewSymbolName, parentSymbol->
GetName() );
488 KIID newDerivedSymbolUuid;
501 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
508 if( sym->m_Uuid == aNewSymbolUuid )
518 newSymbol->
SetName( aNewSymbolName );
525 const_cast<KIID&
>( newSymbol->
m_Uuid ) = aNewSymbolUuid;
528 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Added new symbol to list, size now: %zu",
532 for(
const auto& col :
m_cols )
537 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Initialized field data for new symbol" );
544 wxLogTrace(
traceLibFieldTable,
"Created derived symbol '%s' for library '%s', total tracked: %zu",
556 for(
auto& [
name, element] : fieldStore )
558 element.m_currentData = element.m_originalData;
559 element.m_isModified =
false;
560 element.m_currentlyEmpty =
false;
566 for(
const auto& [symId, fieldStore] :
m_dataStore )
568 for(
const auto& [
name, element] : fieldStore )
570 if( element.m_isModified )
582 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
589 if(
m_cols[aCol].m_fieldName == wxS(
"Keywords" ) )
614 if( lhGroup.
m_Refs.size() == 0 )
616 else if( rhGroup.
m_Refs.size() == 0 )
622 [ ascending ](
const wxString& a,
const wxString& b )
631 wxString lhs = dataModel->
GetValue( lhGroup, sortCol ).Trim(
true ).Trim(
false );
632 wxString rhs = dataModel->
GetValue( rhGroup, sortCol ).Trim(
true ).Trim(
false );
634 if( lhs == rhs && lhGroup.
m_Refs.size() > 1 && rhGroup.
m_Refs.size() > 1 )
636 wxString lhRef = lhGroup.
m_Refs[1]->GetName();
637 wxString rhRef = rhGroup.
m_Refs[1]->GetName();
638 return local_cmp( lhRef, rhRef );
642 return local_cmp( lhs, rhs );
655 std::sort( row.m_Refs.begin(), row.m_Refs.end(),
658 wxString lhs_ref( lhs->GetRef( nullptr ) );
659 wxString rhs_ref( rhs->GetRef( nullptr ) );
660 return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
667 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
675 row.m_ItemNumber = itemNumber++;
685 bool matchFound =
false;
690 for(
size_t i = 0; i <
m_cols.size(); ++i )
708 const wxString& aAttributeName )
710 if( aAttributeName == wxS(
"${DNP}" ) )
711 return aSymbol->
GetDNP() ? wxS(
"1" ) : wxS(
"0" );
713 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
716 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
719 if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
722 if( aAttributeName == wxS(
"Power" ) )
723 return aSymbol->
IsPower() ? wxS(
"1" ) : wxS(
"0" );
725 if( aAttributeName == wxS(
"LocalPower" ) )
726 return aSymbol->
IsLocalPower() ? wxS(
"1" ) : wxS(
"0" );
733 const wxString& aAttributeName,
734 const wxString& aValue )
736 if( aAttributeName == wxS(
"${DNP}" ) )
737 aSymbol->
SetDNP( aValue == wxS(
"1" ) );
738 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
740 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
742 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
744 else if( aAttributeName == wxS(
"LocalPower" ) )
747 if( aValue == wxS(
"0" ) )
752 else if( aAttributeName == wxS(
"Power" ) )
754 if( aValue == wxS(
"0" ) )
760 wxLogDebug(
"Unknown attribute name: %s", aAttributeName );
772 static_cast<WX_GRID*
>( GetView() )->CommitPendingChanges(
true );
774 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (
int)
m_rows.size() );
775 GetView()->ProcessTableMessage( msg );
785 ref->GetName(), ref->m_Uuid.AsString() );
791 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[ref->m_Uuid];
795 auto it = fieldStore.find( col.m_fieldName );
808 bool matchFound =
false;
826 row.m_Refs.push_back( ref );
838 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (
int)
m_rows.size() );
839 GetView()->ProcessTableMessage( msg );
849 std::vector<LIB_DATA_MODEL_ROW> children;
853 bool matchFound =
false;
859 if( children.size() < 2 )
862 std::sort( children.begin(), children.end(),
865 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
869 m_rows.insert(
m_rows.begin() + aRow + 1, children.begin(), children.end() );
871 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, (
int) children.size() );
872 GetView()->ProcessTableMessage( msg );
878 auto firstChild =
m_rows.begin() + aRow + 1;
879 auto afterLastChild = firstChild;
882 while( afterLastChild !=
m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
889 m_rows.erase( firstChild, afterLastChild );
891 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
892 GetView()->ProcessTableMessage( msg );
909 for(
size_t i = 0; i <
m_rows.size(); ++i )
922 for(
size_t i = 0; i <
m_rows.size(); ++i )
931 std::function<
void()> postApplyHandler )
935 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
937 for(
auto& srcData : fieldStore )
939 const wxString& srcName = srcData.first;
945 symbolChangeHandler( symbol );
960 if( srcName.StartsWith(
"__DERIVED_SYMBOL_" ) && srcName.EndsWith(
"__" ) )
963 if( srcName == wxS(
"Keywords" ) )
965 symbol->SetKeyWords( srcValue );
973 SCH_FIELD* destField = symbol->GetField( srcName );
974 bool userAdded = ( col != -1 &&
m_cols[col].m_userAdded );
977 bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
981 const VECTOR2I symbolPos = symbol->GetPosition();
984 symbol->AddField( destField );
997 if( !srcValue.IsEmpty() )
1006 destField->
SetText( srcValue );
1015 std::vector<SCH_FIELD*> symbolFields;
1016 symbol->GetFields( symbolFields );
1021 if( field->IsMandatory() )
1025 if( !fieldStore.contains( field->GetName() ) )
1027 symbolChangeHandler( symbol );
1028 symbol->RemoveField( field );
1037 for(
auto& [fieldName, element] : fieldStore )
1039 if( element.m_createDerivedSymbol )
1046 KIID parentUuid( element.m_originalData );
1050 if( sym->m_Uuid == parentUuid )
1067 if( sym->GetName() == element.m_originalData )
1077 wxString actualDerivedName = element.m_derivedSymbolName;
1080 if( actualDerivedName == parentSymbol->
GetName() )
1083 actualDerivedName = parentSymbol->
GetName() +
"_1";
1087 bool nameExists =
true;
1089 while( nameExists && variant < 100 )
1095 if( sym->GetName() == actualDerivedName )
1104 actualDerivedName = parentSymbol->
GetName() +
"_" + wxString::Format(
"%d", variant );
1111 KIID newDerivedSymbolUuid;
1116 element.m_createDerivedSymbol =
false;
1125 if( postApplyHandler )
1149 return wxGRID_VALUE_BOOL;
1151 return wxGridTableBase::GetTypeName( row, col );
1157 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(),
nullptr );
1159 const wxString& fieldName =
m_cols[aCol].m_fieldName;
1165 it->second->IncRef();
1169 wxGridCellRenderer* stripedRenderer =
nullptr;
1174 stripedRenderer->IncRef();
1178 stripedRenderer->IncRef();
1179 return stripedRenderer;
1186 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 aExcludeFromBoard) 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.
bool GetExcludedFromBoard() const override
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
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
@ 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