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 if(
auto node =
m_dataStore[symbol->m_Uuid].extract(
m_cols[aCol].m_fieldName ) )
132 node.key() = newName;
133 node.mapped().m_isModified =
true;
134 m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
138 m_cols[aCol].m_fieldName = newName;
139 m_cols[aCol].m_label = newName;
146 for(
size_t i = 0; i <
m_cols.size(); i++ )
148 if(
m_cols[i].m_fieldName == aFieldName )
158 size_t foundCount = 0;
160 if( aNewOrder.size() >
m_cols.size() )
161 wxLogDebug(
"New order contains more fields than existing columns." );
163 for(
const wxString& newField : aNewOrder )
166 for(
size_t i = 0; i <
m_cols.size() && foundCount <
m_cols.size(); i++ )
168 if(
m_cols[i].m_fieldName == newField )
178 wxLogDebug(
"Field '%s' not found in existing columns.", newField );
181 if( foundCount !=
m_cols.size() && foundCount != aNewOrder.size() )
183 wxLogDebug(
"Not all fields in the new order were found in the existing columns." );
191 for(
int col = 0; col < aCol; ++col )
210 std::set<wxString> mixedValues;
213 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(), fieldValue );
226 if( listMixedValues )
227 mixedValues.insert( refFieldValue );
228 else if( ref ==
group.m_Refs.front() )
229 fieldValue = refFieldValue;
230 else if( fieldValue != refFieldValue )
234 if( listMixedValues )
236 fieldValue = wxEmptyString;
238 for(
const wxString& value : mixedValues )
240 if( value.IsEmpty() )
242 else if( fieldValue.IsEmpty() )
245 fieldValue +=
"," + value;
255 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
276 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
283 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
284 return m_cols[aCol].m_isCheckbox;
290 wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
298 wxGridCellAttr* newAttr =
m_colAttrs[aCol]->Clone();
301 if( attr->HasBackgroundColour() && !newAttr->HasBackgroundColour() )
302 newAttr->SetBackgroundColour( attr->GetBackgroundColour() );
303 if( attr->HasTextColour() && !newAttr->HasTextColour() )
304 newAttr->SetTextColour( attr->GetTextColour() );
305 if( attr->HasFont() && !newAttr->HasFont() )
306 newAttr->SetFont( attr->GetFont() );
318 attr =
new wxGridCellAttr;
321 bool rowModified =
false;
322 bool cellModified =
false;
323 bool cellEmpty =
true;
324 bool blankModified =
false;
326 const wxString& fieldName =
m_cols[aCol].m_fieldName;
342 blankModified =
true;
348 if(
m_dataStore[ref->m_Uuid][col.m_fieldName].m_isModified )
356 if( cellModified && rowModified && !cellEmpty )
365 if( stripedRenderer )
367 attr->SetRenderer( stripedRenderer );
368 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
372 if(
m_dataStore[ref->m_Uuid][fieldName].m_isModified )
374 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
true;
376 if(
m_dataStore[ref->m_Uuid][fieldName].m_currentlyEmpty )
378 if(
m_dataStore[ref->m_Uuid][fieldName].m_originallyEmpty )
380 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
382 else if(
m_dataStore[ref->m_Uuid][fieldName].m_originalData.empty() )
384 attr->SetBackgroundColour( wxColour( 180, 220, 180 ) );
388 attr->SetBackgroundColour( wxColour( 220, 180, 180 ) );
391 else if(
m_dataStore[ref->m_Uuid][fieldName].m_currentData.IsEmpty() )
393 attr->SetBackgroundColour( wxColour( 180, 200, 180 ) );
397 attr->SetBackgroundColour( wxColour( 200, 180, 180 ) );
405 bool wasStriped =
false;
409 if(
m_dataStore[ref->m_Uuid][fieldName].m_isStriped )
412 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
false;
418 attr =
new wxGridCellAttr;
421 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
424 attr->SetBackgroundColour( wxColour( 192, 255, 192 ) );
431 if( attr->HasFont() )
432 font = attr->GetFont();
434 font = GetView()->GetDefaultCellFont();
441 attr->SetFont( font );
451 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
452 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
455 const wxString& fieldName =
m_cols[aCol].m_fieldName;
457 std::map<wxString, LIB_DATA_ELEMENT>& parentFieldStore =
m_dataStore[parentSymbol->
m_Uuid];
460 wxString derivedSymbolFieldName =
"__DERIVED_SYMBOL_" + fieldName +
"__";
470 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Parent symbol name='%s', UUID='%s'",
472 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Stored creation request for symbol '%s' under parent UUID %s, special field '%s'",
473 aNewSymbolName, parentSymbol->
m_Uuid.
AsString(), derivedSymbolFieldName );
480 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
481 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
485 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
486 aNewSymbolName, parentSymbol->
GetName() );
489 KIID newDerivedSymbolUuid;
502 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
509 if( sym->m_Uuid == aNewSymbolUuid )
519 newSymbol->
SetName( aNewSymbolName );
526 const_cast<KIID&
>( newSymbol->
m_Uuid ) = aNewSymbolUuid;
529 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Added new symbol to list, size now: %zu",
533 for(
const auto& col :
m_cols )
538 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Initialized field data for new symbol" );
545 wxLogTrace(
traceLibFieldTable,
"Created derived symbol '%s' for library '%s', total tracked: %zu",
557 for(
auto& [
name, element] : fieldStore )
559 element.m_currentData = element.m_originalData;
560 element.m_isModified =
false;
561 element.m_currentlyEmpty =
false;
567 for(
const auto& [symId, fieldStore] :
m_dataStore )
569 for(
const auto& [
name, element] : fieldStore )
571 if( element.m_isModified )
583 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
590 if(
m_cols[aCol].m_fieldName == wxS(
"Keywords" ) )
615 if( lhGroup.
m_Refs.size() == 0 )
617 else if( rhGroup.
m_Refs.size() == 0 )
623 [ ascending ](
const wxString& a,
const wxString& b )
632 wxString lhs = dataModel->
GetValue( lhGroup, sortCol ).Trim(
true ).Trim(
false );
633 wxString rhs = dataModel->
GetValue( rhGroup, sortCol ).Trim(
true ).Trim(
false );
635 if( lhs == rhs && lhGroup.
m_Refs.size() > 1 && rhGroup.
m_Refs.size() > 1 )
637 wxString lhRef = lhGroup.
m_Refs[1]->GetName();
638 wxString rhRef = rhGroup.
m_Refs[1]->GetName();
639 return local_cmp( lhRef, rhRef );
643 return local_cmp( lhs, rhs );
656 std::sort( row.m_Refs.begin(), row.m_Refs.end(),
659 wxString lhs_ref( lhs->GetRef( nullptr ) );
660 wxString rhs_ref( rhs->GetRef( nullptr ) );
661 return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
668 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
676 row.m_ItemNumber = itemNumber++;
686 bool matchFound =
false;
691 for(
size_t i = 0; i <
m_cols.size(); ++i )
709 const wxString& aAttributeName )
711 if( aAttributeName == wxS(
"${DNP}" ) )
712 return aSymbol->
GetDNP() ? wxS(
"1" ) : wxS(
"0" );
714 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
717 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
720 if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
723 if( aAttributeName == wxS(
"Power" ) )
724 return aSymbol->
IsPower() ? wxS(
"1" ) : wxS(
"0" );
726 if( aAttributeName == wxS(
"LocalPower" ) )
727 return aSymbol->
IsLocalPower() ? wxS(
"1" ) : wxS(
"0" );
734 const wxString& aAttributeName,
735 const wxString& aValue )
737 if( aAttributeName == wxS(
"${DNP}" ) )
738 aSymbol->
SetDNP( aValue == wxS(
"1" ) );
739 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
741 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
743 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
745 else if( aAttributeName == wxS(
"LocalPower" ) )
748 if( aValue == wxS(
"0" ) )
753 else if( aAttributeName == wxS(
"Power" ) )
755 if( aValue == wxS(
"0" ) )
761 wxLogDebug(
"Unknown attribute name: %s", aAttributeName );
773 static_cast<WX_GRID*
>( GetView() )->CommitPendingChanges(
true );
775 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (
int)
m_rows.size() );
776 GetView()->ProcessTableMessage( msg );
786 ref->GetName(), ref->m_Uuid.AsString() );
792 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[ref->m_Uuid];
796 auto it = fieldStore.find( col.m_fieldName );
809 bool matchFound =
false;
827 row.m_Refs.push_back( ref );
839 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (
int)
m_rows.size() );
840 GetView()->ProcessTableMessage( msg );
850 std::vector<LIB_DATA_MODEL_ROW> children;
854 bool matchFound =
false;
860 if( children.size() < 2 )
863 std::sort( children.begin(), children.end(),
866 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
870 m_rows.insert(
m_rows.begin() + aRow + 1, children.begin(), children.end() );
872 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, (
int) children.size() );
873 GetView()->ProcessTableMessage( msg );
879 auto firstChild =
m_rows.begin() + aRow + 1;
880 auto afterLastChild = firstChild;
883 while( afterLastChild !=
m_rows.end() && afterLastChild->m_Flag ==
CHILD_ITEM )
890 m_rows.erase( firstChild, afterLastChild );
892 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
893 GetView()->ProcessTableMessage( msg );
910 for(
size_t i = 0; i <
m_rows.size(); ++i )
923 for(
size_t i = 0; i <
m_rows.size(); ++i )
932 std::function<
void()> postApplyHandler )
936 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
938 for(
auto& srcData : fieldStore )
940 const wxString& srcName = srcData.first;
946 symbolChangeHandler( symbol );
961 if( srcName.StartsWith(
"__DERIVED_SYMBOL_" ) && srcName.EndsWith(
"__" ) )
964 if( srcName == wxS(
"Keywords" ) )
966 symbol->SetKeyWords( srcValue );
974 SCH_FIELD* destField = symbol->GetField( srcName );
975 bool userAdded = ( col != -1 &&
m_cols[col].m_userAdded );
978 bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
982 const VECTOR2I symbolPos = symbol->GetPosition();
985 symbol->AddField( destField );
998 if( !srcValue.IsEmpty() )
1007 destField->
SetText( srcValue );
1016 std::vector<SCH_FIELD*> symbolFields;
1017 symbol->GetFields( symbolFields );
1022 if( field->IsMandatory() )
1026 if( !fieldStore.contains( field->GetName() ) )
1028 symbolChangeHandler( symbol );
1029 symbol->RemoveField( field );
1038 for(
auto& [fieldName, element] : fieldStore )
1040 if( element.m_createDerivedSymbol )
1047 KIID parentUuid( element.m_originalData );
1051 if( sym->m_Uuid == parentUuid )
1068 if( sym->GetName() == element.m_originalData )
1078 wxString actualDerivedName = element.m_derivedSymbolName;
1081 if( actualDerivedName == parentSymbol->
GetName() )
1084 actualDerivedName = parentSymbol->
GetName() +
"_1";
1088 bool nameExists =
true;
1090 while( nameExists && variant < 100 )
1096 if( sym->GetName() == actualDerivedName )
1105 actualDerivedName = parentSymbol->
GetName() +
"_" + wxString::Format(
"%d", variant );
1112 KIID newDerivedSymbolUuid;
1117 element.m_createDerivedSymbol =
false;
1126 if( postApplyHandler )
1150 return wxGRID_VALUE_BOOL;
1152 return wxGridTableBase::GetTypeName( row, col );
1158 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(),
nullptr );
1160 const wxString& fieldName =
m_cols[aCol].m_fieldName;
1166 it->second->IncRef();
1170 wxGridCellRenderer* stripedRenderer =
nullptr;
1175 stripedRenderer->IncRef();
1179 stripedRenderer->IncRef();
1180 return stripedRenderer;
1187 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
Definition for symbol library class.
@ 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