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 std::map<int, wxGridCellAttr*> newColAttrs;
134 newColAttrs[col - 1] = attr;
136 newColAttrs[col] = attr;
141 if( wxGrid*
grid = GetView() )
143 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_COLS_DELETED, aCol, 1 );
144 grid->ProcessTableMessage( msg );
156 if(
auto node =
m_dataStore[symbol->m_Uuid].extract(
m_cols[aCol].m_fieldName ) )
158 node.key() = newName;
159 node.mapped().m_isModified =
true;
160 m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
164 m_cols[aCol].m_fieldName = newName;
165 m_cols[aCol].m_label = newName;
172 for(
size_t i = 0; i <
m_cols.size(); i++ )
174 if(
m_cols[i].m_fieldName == aFieldName )
184 size_t foundCount = 0;
186 if( aNewOrder.size() >
m_cols.size() )
187 wxLogDebug(
"New order contains more fields than existing columns." );
189 for(
const wxString& newField : aNewOrder )
192 for(
size_t i = 0; i <
m_cols.size() && foundCount <
m_cols.size(); i++ )
194 if(
m_cols[i].m_fieldName == newField )
204 wxLogDebug(
"Field '%s' not found in existing columns.", newField );
207 if( foundCount !=
m_cols.size() && foundCount != aNewOrder.size() )
209 wxLogDebug(
"Not all fields in the new order were found in the existing columns." );
217 for(
int col = 0; col < aCol; ++col )
236 std::set<wxString> mixedValues;
239 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(), fieldValue );
252 if( listMixedValues )
253 mixedValues.insert( refFieldValue );
254 else if( ref ==
group.m_Refs.front() )
255 fieldValue = refFieldValue;
256 else if( fieldValue != refFieldValue )
260 if( listMixedValues )
262 fieldValue = wxEmptyString;
264 for(
const wxString& value : mixedValues )
266 if( value.IsEmpty() )
268 else if( fieldValue.IsEmpty() )
271 fieldValue +=
"," + value;
281 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
302 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
309 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
310 return m_cols[aCol].m_isCheckbox;
316 wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
324 wxGridCellAttr* newAttr =
m_colAttrs[aCol]->Clone();
327 if( attr->HasBackgroundColour() && !newAttr->HasBackgroundColour() )
328 newAttr->SetBackgroundColour( attr->GetBackgroundColour() );
329 if( attr->HasTextColour() && !newAttr->HasTextColour() )
330 newAttr->SetTextColour( attr->GetTextColour() );
331 if( attr->HasFont() && !newAttr->HasFont() )
332 newAttr->SetFont( attr->GetFont() );
344 attr =
new wxGridCellAttr;
347 bool rowModified =
false;
348 bool cellModified =
false;
349 bool cellEmpty =
true;
350 bool blankModified =
false;
352 const wxString& fieldName =
m_cols[aCol].m_fieldName;
368 blankModified =
true;
374 if(
m_dataStore[ref->m_Uuid][col.m_fieldName].m_isModified )
382 if( cellModified && rowModified && !cellEmpty )
391 if( stripedRenderer )
393 attr->SetRenderer( stripedRenderer );
394 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
398 if(
m_dataStore[ref->m_Uuid][fieldName].m_isModified )
400 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
true;
402 if(
m_dataStore[ref->m_Uuid][fieldName].m_currentlyEmpty )
404 if(
m_dataStore[ref->m_Uuid][fieldName].m_originallyEmpty )
406 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
408 else if(
m_dataStore[ref->m_Uuid][fieldName].m_originalData.empty() )
410 attr->SetBackgroundColour( wxColour( 180, 220, 180 ) );
414 attr->SetBackgroundColour( wxColour( 220, 180, 180 ) );
417 else if(
m_dataStore[ref->m_Uuid][fieldName].m_currentData.IsEmpty() )
419 attr->SetBackgroundColour( wxColour( 180, 200, 180 ) );
423 attr->SetBackgroundColour( wxColour( 200, 180, 180 ) );
431 bool wasStriped =
false;
435 if(
m_dataStore[ref->m_Uuid][fieldName].m_isStriped )
438 m_dataStore[ref->m_Uuid][fieldName].m_isStriped =
false;
444 attr =
new wxGridCellAttr;
447 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
450 attr->SetBackgroundColour( wxColour( 192, 255, 192 ) );
457 if( attr->HasFont() )
458 font = attr->GetFont();
460 font = GetView()->GetDefaultCellFont();
467 attr->SetFont( font );
477 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
478 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
481 const wxString& fieldName =
m_cols[aCol].m_fieldName;
483 std::map<wxString, LIB_DATA_ELEMENT>& parentFieldStore =
m_dataStore[parentSymbol->
m_Uuid];
486 wxString derivedSymbolFieldName =
"__DERIVED_SYMBOL_" + fieldName +
"__";
496 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Parent symbol name='%s', UUID='%s'",
498 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbol: Stored creation request for symbol '%s' under parent UUID %s, special field '%s'",
499 aNewSymbolName, parentSymbol->
m_Uuid.
AsString(), derivedSymbolFieldName );
506 wxCHECK_RET( aRow >= 0 && aRow < (
int)
m_rows.size(),
"Invalid Row Number" );
507 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(),
"Invalid Column Number" );
511 wxLogTrace(
traceLibFieldTable,
"CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
512 aNewSymbolName, parentSymbol->
GetName() );
515 KIID newDerivedSymbolUuid;
528 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
535 if( sym->m_Uuid == aNewSymbolUuid )
545 newSymbol->
SetName( aNewSymbolName );
552 const_cast<KIID&
>( newSymbol->
m_Uuid ) = aNewSymbolUuid;
555 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Added new symbol to list, size now: %zu",
559 for(
const auto& col :
m_cols )
564 wxLogTrace(
traceLibFieldTable,
"createActualDerivedSymbol: Initialized field data for new symbol" );
571 wxLogTrace(
traceLibFieldTable,
"Created derived symbol '%s' for library '%s', total tracked: %zu",
583 for(
auto& [
name, element] : fieldStore )
585 element.m_currentData = element.m_originalData;
586 element.m_isModified =
false;
587 element.m_currentlyEmpty =
false;
593 for(
const auto& [symId, fieldStore] :
m_dataStore )
595 for(
const auto& [
name, element] : fieldStore )
597 if( element.m_isModified )
609 wxCHECK_RET( aCol >= 0 && aCol < (
int)
m_cols.size(), wxS(
"Invalid column number" ) );
616 if(
m_cols[aCol].m_fieldName == wxS(
"Keywords" ) )
641 if( lhGroup.
m_Refs.size() == 0 )
643 else if( rhGroup.
m_Refs.size() == 0 )
649 [ ascending ](
const wxString& a,
const wxString& b )
658 wxString lhs = dataModel->
GetValue( lhGroup, sortCol ).Trim(
true ).Trim(
false );
659 wxString rhs = dataModel->
GetValue( rhGroup, sortCol ).Trim(
true ).Trim(
false );
661 if( lhs == rhs && lhGroup.
m_Refs.size() > 1 && rhGroup.
m_Refs.size() > 1 )
663 wxString lhRef = lhGroup.
m_Refs[1]->GetName();
664 wxString rhRef = rhGroup.
m_Refs[1]->GetName();
665 return local_cmp( lhRef, rhRef );
669 return local_cmp( lhs, rhs );
682 std::sort( row.m_Refs.begin(), row.m_Refs.end(),
685 wxString lhs_ref( lhs->GetRef( nullptr ) );
686 wxString rhs_ref( rhs->GetRef( nullptr ) );
687 return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
694 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
702 row.m_ItemNumber = itemNumber++;
712 bool matchFound =
false;
717 for(
size_t i = 0; i <
m_cols.size(); ++i )
735 const wxString& aAttributeName )
737 if( aAttributeName == wxS(
"${DNP}" ) )
738 return aSymbol->
GetDNP() ? wxS(
"1" ) : wxS(
"0" );
740 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
743 if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
746 if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
749 if( aAttributeName == wxS(
"Power" ) )
750 return aSymbol->
IsPower() ? wxS(
"1" ) : wxS(
"0" );
752 if( aAttributeName == wxS(
"LocalPower" ) )
753 return aSymbol->
IsLocalPower() ? wxS(
"1" ) : wxS(
"0" );
760 const wxString& aAttributeName,
761 const wxString& aValue )
763 if( aAttributeName == wxS(
"${DNP}" ) )
764 aSymbol->
SetDNP( aValue == wxS(
"1" ) );
765 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
767 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
769 else if( aAttributeName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
771 else if( aAttributeName == wxS(
"LocalPower" ) )
774 if( aValue == wxS(
"0" ) )
779 else if( aAttributeName == wxS(
"Power" ) )
781 if( aValue == wxS(
"0" ) )
787 wxLogDebug(
"Unknown attribute name: %s", aAttributeName );
799 static_cast<WX_GRID*
>( GetView() )->CommitPendingChanges(
true );
801 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (
int)
m_rows.size() );
802 GetView()->ProcessTableMessage( msg );
812 ref->GetName(), ref->m_Uuid.AsString() );
818 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[ref->m_Uuid];
822 auto it = fieldStore.find( col.m_fieldName );
835 bool matchFound =
false;
853 row.m_Refs.push_back( ref );
865 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (
int)
m_rows.size() );
866 GetView()->ProcessTableMessage( msg );
876 std::vector<LIB_DATA_MODEL_ROW> children;
880 bool matchFound =
false;
886 if( children.size() < 2 )
889 std::sort( children.begin(), children.end(),
892 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
896 m_rows.insert(
m_rows.begin() + aRow + 1, children.begin(), children.end() );
898 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, (
int) children.size() );
899 GetView()->ProcessTableMessage( msg );
905 auto firstChild =
m_rows.begin() + aRow + 1;
906 auto afterLastChild = firstChild;
909 while( afterLastChild !=
m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
916 m_rows.erase( firstChild, afterLastChild );
918 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
919 GetView()->ProcessTableMessage( msg );
936 for(
size_t i = 0; i <
m_rows.size(); ++i )
949 for(
size_t i = 0; i <
m_rows.size(); ++i )
958 std::function<
void()> postApplyHandler )
962 std::map<wxString, LIB_DATA_ELEMENT>& fieldStore =
m_dataStore[symbol->m_Uuid];
964 for(
auto& srcData : fieldStore )
966 const wxString& srcName = srcData.first;
972 symbolChangeHandler( symbol );
987 if( srcName.StartsWith(
"__DERIVED_SYMBOL_" ) && srcName.EndsWith(
"__" ) )
990 if( srcName == wxS(
"Keywords" ) )
992 symbol->SetKeyWords( srcValue );
1000 SCH_FIELD* destField = symbol->GetField( srcName );
1001 bool userAdded = ( col != -1 &&
m_cols[col].m_userAdded );
1004 bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
1008 const VECTOR2I symbolPos = symbol->GetPosition();
1011 symbol->AddField( destField );
1024 if( !srcValue.IsEmpty() )
1033 destField->
SetText( srcValue );
1042 std::vector<SCH_FIELD*> symbolFields;
1043 symbol->GetFields( symbolFields );
1048 if( field->IsMandatory() )
1052 if( !fieldStore.contains( field->GetName() ) )
1054 symbolChangeHandler( symbol );
1055 symbol->RemoveField( field );
1063 for(
auto& [fieldName, element] : fieldStore )
1065 if( element.m_createDerivedSymbol )
1072 KIID parentUuid( element.m_originalData );
1076 if( sym->m_Uuid == parentUuid )
1093 if( sym->GetName() == element.m_originalData )
1103 wxString actualDerivedName = element.m_derivedSymbolName;
1106 if( actualDerivedName == parentSymbol->
GetName() )
1109 actualDerivedName = parentSymbol->
GetName() +
"_1";
1113 bool nameExists =
true;
1115 while( nameExists && variant < 100 )
1121 if( sym->GetName() == actualDerivedName )
1130 actualDerivedName = parentSymbol->
GetName() +
"_" + wxString::Format(
"%d", variant );
1137 KIID newDerivedSymbolUuid;
1142 element.m_createDerivedSymbol =
false;
1151 if( postApplyHandler )
1175 return wxGRID_VALUE_BOOL;
1177 return wxGridTableBase::GetTypeName( row, col );
1183 wxCHECK( aCol >= 0 && aCol < (
int)
m_cols.size(),
nullptr );
1185 const wxString& fieldName =
m_cols[aCol].m_fieldName;
1191 it->second->IncRef();
1195 wxGridCellRenderer* stripedRenderer =
nullptr;
1200 stripedRenderer->IncRef();
1204 stripedRenderer->IncRef();
1205 return stripedRenderer;
1212 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
@ 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