23#include <unordered_set>
101template <
typename ITEM_TYPE>
107 m_items.push_back( aFirstItem );
132 virtual void AddColumn(
const wxString& aFieldName,
const wxString& aLabel,
bool aAddedByUser ) = 0;
221 virtual wxString
GetExportValue(
int aRow,
int aCol,
const wxString& aRefDelimiter,
222 const wxString& aRefRangeDelimiter ) = 0;
342 void Draw( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC,
const wxRect& aRect,
int aRow,
int aCol,
343 bool isSelected )
override;
345 wxSize
GetBestSize( wxGrid& aGrid, wxGridCellAttr& aAttr, wxDC& aDC,
int aRow,
int aCol )
override;
347 wxGridCellRenderer*
Clone()
const override;
356template <
typename ITEM_TYPE>
360 void AddColumn(
const wxString& aFieldName,
const wxString& aLabel,
361 bool aAddedByUser )
override
369 m_cols.push_back( { aFieldName, aLabel, aAddedByUser,
false,
false } );
377 if( wxGrid*
grid = GetView() )
379 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1 );
380 grid->ProcessTableMessage( msg );
390 wxCHECK_RET( aRow >= 0 && aRow <
static_cast<int>(
m_rows.size() ),
"Invalid Row Number" );
391 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
396 const wxString& fieldName =
m_cols[aCol].m_fieldName;
398 for(
const ITEM_TYPE& item :
m_rows[aRow].m_items )
411 wxCHECK_MSG( aRow >= 0 && aRow <
static_cast<int>(
m_rows.size() ),
false,
"Invalid Row Number" );
412 wxCHECK_MSG( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false,
"Invalid Column Number" );
414 for(
const ITEM_TYPE& item :
m_rows[aRow].m_items )
432 wxCHECK_MSG( aRow >= 0 && aRow <
static_cast<int>(
m_rows.size() ),
false,
"Invalid Row Number" );
433 wxCHECK_MSG( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false,
"Invalid Column Number" );
435 for(
const ITEM_TYPE& item :
m_rows[aRow].m_items )
451 wxCHECK( aRow >= 0 && aRow < (
int)
m_rows.size(), std::vector<KIID_PATH>() );
453 std::vector<KIID_PATH> keys;
455 for(
const ITEM_TYPE& item :
m_rows[aRow].m_items )
464 wxCHECK( aRow >= 0 && aRow < (
int)
m_rows.size(), std::vector<ITEM_TYPE>() );
465 return m_rows[aRow].m_items;
476 wxCHECK_RET( aRow >= 0 && aRow <
static_cast<int>(
m_rows.size() ),
"Invalid Row Number" );
478 for(
const ITEM_TYPE& item :
m_rows[aRow].m_items )
502 std::vector<DATA_MODEL_ROW<ITEM_TYPE>> children;
504 for( ITEM_TYPE& ref :
m_rows[aRow].m_items )
506 bool matchFound =
false;
516 child.m_items.push_back( ref );
522 children.emplace_back( ref, ROW_STATE::EXPANDED_CHILD );
525 if( children.size() < 2 )
528 std::sort( children.begin(), children.end(),
532 return cmpRows( lhs, rhs, m_sortColumn, m_sortAscending );
535 m_rows[aRow].m_state = ROW_STATE::EXPANDED_PARENT;
536 m_rows.insert(
m_rows.begin() + aRow + 1, children.begin(), children.end() );
538 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow + 1, children.size() );
539 GetView()->ProcessTableMessage( msg );
545 auto firstChild =
m_rows.begin() + aRow + 1;
546 auto afterLastChild = firstChild;
549 while( afterLastChild !=
m_rows.end() && afterLastChild->m_state == ROW_STATE::EXPANDED_CHILD )
555 m_rows[aRow].m_state = ROW_STATE::COLLAPSED;
556 m_rows.erase( firstChild, afterLastChild );
558 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
559 GetView()->ProcessTableMessage( msg );
565 if(
m_rows[aRow].m_state == ROW_STATE::COLLAPSED )
567 else if(
m_rows[aRow].m_state == ROW_STATE::EXPANDED_PARENT )
574 for(
size_t i = 0; i <
m_rows.size(); ++i )
576 if(
m_rows[i].m_state == ROW_STATE::EXPANDED_PARENT )
579 m_rows[i].m_state = ROW_STATE::COLLAPSED_DURING_SORT;
587 for(
size_t i = 0; i <
m_rows.size(); ++i )
589 if(
m_rows[i].m_state == ROW_STATE::COLLAPSED_DURING_SORT )
595 const wxString& refDelimiter = wxT(
", " ),
596 const wxString& refRangeDelimiter = wxT(
"-" ),
597 bool resolveVars =
false,
bool listMixedValues =
false )
599 std::vector<ITEM_TYPE> items;
600 std::set<wxString> mixedValues;
603 for(
const ITEM_TYPE& item : aRow.
m_items )
607 items.push_back( item );
611 wxString itemFieldValue;
617 itemFieldValue = wxS(
"1" );
641 if( listMixedValues )
642 mixedValues.insert( itemFieldValue );
643 else if( &item == &aRow.
m_items.front() )
644 fieldValue = itemFieldValue;
645 else if( fieldValue != itemFieldValue )
650 if( listMixedValues )
652 fieldValue = wxEmptyString;
654 for(
const wxString& value : mixedValues )
656 if( value.IsEmpty() )
658 else if( fieldValue.IsEmpty() )
661 fieldValue +=
"," + value;
668 std::sort( items.begin(), items.end(),
669 [
this](
const ITEM_TYPE& lhs,
const ITEM_TYPE& rhs ) ->
bool
671 return cmpRowItems( lhs, rhs );
674 auto logicalEnd = std::unique( items.begin(), items.end(),
675 [
this](
const ITEM_TYPE& lhs,
const ITEM_TYPE& rhs ) ->
bool
677 return unitMatch( lhs, rhs );
680 items.erase( logicalEnd, items.end() );
688 std::vector<wxString> itemIdentifiers;
690 for(
const ITEM_TYPE& item : items )
702 for(
const wxString& itemIdentifier : itemIdentifiers )
704 if( !fieldValue.IsEmpty() )
705 fieldValue += refDelimiter;
707 fieldValue += itemIdentifier;
712 fieldValue = wxString::Format( wxT(
"%d" ), (
int) items.size() );
714 fieldValue = wxString::Format( wxT(
"%d" ), aRow.
m_itemNumber );
722 wxCHECK( aRow >= 0 && aRow <
GetNumberRows(), wxEmptyString );
723 wxCHECK( aCol >= 0 && aCol <
GetNumberCols(), wxEmptyString );
734 const wxString& refRangeDelimiter )
override
767 return aMatcher.
Find( aReference.Lower() );
769 for(
size_t i = 0; i <
m_cols.size(); ++i )
798 if( aMatcher.
Find( value.Lower() ) )
824 for(
const ITEM_TYPE& item : aRow.
m_items )
834 int aSortCol,
bool aAscending )
839 else if( rhRow.
m_items.empty() )
845 [aAscending](
const auto a,
const auto b )
857 wxString lhs = this->
GetGroupedValue( lhRow, aSortCol, wxT(
", " ), wxT(
"-" ),
true )
860 wxString rhs = this->
GetGroupedValue( rhRow, aSortCol, wxT(
", " ), wxT(
"-" ),
true )
878 virtual bool cmpRowItems(
const ITEM_TYPE& lhItem,
const ITEM_TYPE& rhItem )
883 virtual bool unitMatch(
const ITEM_TYPE& lhItem,
const ITEM_TYPE& rhItem ) = 0;
885 bool groupMatch(
const ITEM_TYPE& lhItem,
const ITEM_TYPE& rhItem )
887 bool matchFound =
false;
889 for(
size_t i = 0; i <
m_cols.size(); ++i )
894 int col =
static_cast<int>( i );
910 const wxString& fieldName =
m_cols[i].m_fieldName;
925 if( lhEffectiveValue != rhEffectiveValue )
965 std::sort( row.m_items.begin(), row.m_items.end(),
966 [
this](
const ITEM_TYPE& lhs,
const ITEM_TYPE& rhs ) ->
bool
968 return cmpRowItems( lhs, rhs );
975 return cmpRows( lhs, rhs, m_sortColumn, m_sortAscending );
983 row.m_itemNumber = itemNumber++;
996 virtual bool getLiveFieldValue(
const ITEM_TYPE& aItem,
const wxString& aFieldName, wxString& aValue ) = 0;
1003 static const std::map<wxString, wxString> emptyFields;
1010 return itemIt->second;
1023 const std::map<wxString, wxString>& fields =
getStoredFields( aItem );
1024 auto fieldIt = fields.find( aFieldName );
1026 if( fieldIt == fields.end() )
1029 aValue = fieldIt->second;
1037 const wxString& aValue )
1059 itemIt->second.erase( aFieldName );
1070 wxString storedValue;
1074 return liveFieldPresent != storedFieldPresent || liveValue != storedValue;
1139 std::vector<DATA_MODEL_ROW<ITEM_TYPE>>
m_rows;
bool Find(const wxString &aTerm, int &aMatchersTriggered, int &aPosition)
Look in all existing matchers, return the earliest match of any of the existing.
void SetSelectionItems(const std::unordered_set< KIID_PATH > &aItems)
bool cellUsesResolvedTextRenderer(int aRow, int aCol)
const wxString & GetCurrentVariant() const
virtual bool fieldIsItemProperty(const wxString &aFieldName) const
void SetVariantNames(const std::vector< wxString > &aVariantNames)
bool cellUsesUrlEditor(int aRow, int aCol)
~FIELDS_TABLE_DATA_MODEL_BASE() override
FIELDS_TABLE_DATA_MODEL_BASE()
BOM_FILTER_SCOPE GetFilterScope() const
virtual bool IsCellEdited(int aRow, int aCol)=0
void SetExcludeDNP(bool aExclude)
bool ColIsComputed(int aCol) const
void SetSorting(int aCol, bool aAscending)
int GetNumberCols() override
void MoveColumn(int aCol, int aNewPos)
wxString GetColFieldName(int aCol)
virtual void ClearCell(int aRow, int aCol)=0
bool ColIsValue(int aCol) const
bool IsEmptyCell(int aRow, int aCol) override
bool ColIsItemProperty(int aCol) const
void SetShowColumn(int aCol, bool aShow)
void SetIncludeExcludedFromBOM(bool aInclude)
bool IsRowEdited(int aRow)
Return true if any cell in the row has been edited.
wxGridCellAttr * applyFieldPresenceRenderer(wxGridCellAttr *aAttr, int aRow, int aCol)
bool CanClearCell(int aRow, int aCol)
std::vector< BOM_FIELD > GetFieldsOrdered()
bool ColIsAttribute(int aCol) const
static const wxString QUANTITY_VARIABLE
void applyResolvedTextRenderer(wxGridCellAttr *aAttr, bool aApplyTint)
static const wxString ITEM_NUMBER_VARIABLE
void commitPendingGridChanges()
virtual bool ColIsReadOnly(int aCol) const
virtual void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser)=0
bool HasUndoStateSerialization() const override
Optional identity-based serialization for the host dialog's Ctrl+Z/Ctrl+Y.
bool GetGroupColumn(int aCol)
wxString Export(const BOM_FMT_PRESET &aSettings)
wxGridCellRenderer * m_resolvedTextRenderer
bool ColIsReference(int aCol) const
virtual wxString GetExportValue(int aRow, int aCol, const wxString &aRefDelimiter, const wxString &aRefRangeDelimiter)=0
virtual bool ColIsItemIdentifier(int aCol) const
Reference for symbol/fields tables, lib_id for lib tables.
void SetColLabelValue(int aCol, const wxString &aLabel) override
wxGridCellAttr * cloneUrlEditorAttr()
void SetFilterScope(BOM_FILTER_SCOPE aScope)
bool ColIsQuantity(int aCol) const
virtual bool fieldIsAttribute(const wxString &aFieldName) const
BOM_PRESET GetBomSettings()
wxGridCellAttr * applyCellDecorations(wxGridCellAttr *aAttr, int aRow, int aCol)
virtual wxString getAttributeResolvedValue(const wxString &aFieldName, bool aValue) const
void ClearSelectionItems()
void SetFieldsOrder(const std::vector< wxString > &aNewOrder)
virtual void RevertRow(int aRow)=0
bool ColIsFootprint(int aCol) const
virtual bool IsCellReadOnly(int aRow, int aCol)
int GetFieldNameCol(const wxString &aFieldName) const
virtual wxString GetResolvedValue(int aRow, int aCol)=0
void RemoveColumn(int aCol)
bool GetIncludeExcludedFromBOM()
wxString SerializeUndoState() const override
void SetGroupingEnabled(bool aGroup)
bool IsExpanderColumn(int aCol) const override
std::unordered_set< KIID_PATH > m_selectionItems
int GetColDataWidth(int aCol)
bool ColIsItemNumber(int aCol) const
const wxString & GetFilter()
std::vector< wxString > m_variantNames
Variant names for multi-variant DNP filtering.
virtual void ExpandCollapseRow(int aRow)=0
wxGridCellRenderer * m_stripedRenderer
std::vector< DATA_MODEL_COL > m_cols
bool GetGroupingEnabled()
const std::vector< wxString > & GetVariantNames() const
void RestoreUndoState(const wxString &aState) override
void SetCurrentVariant(const wxString &aVariantName)
Set the current variant name for highlighting purposes.
void RenameColumn(int aCol, const wxString &newName)
void SetGroupColumn(int aCol, bool aGroup)
void SetFilter(const wxString &aFilter)
wxString GetColLabelValue(int aCol) override
virtual std::vector< KIID_PATH > GetRowItemKeys(int aRow) const =0
Return the stable data-store keys of every item represented by a row.
bool GetShowColumn(int aCol)
void ApplyBomPreset(const BOM_PRESET &aPreset)
virtual void RebuildRows()=0
virtual bool IsCellClear(int aRow, int aCol)=0
BOM_FILTER_SCOPE m_filterScope
wxString m_currentVariant
Current variant name for highlighting.
bool m_rebuildsEnabled
Items included by the user selection scope.
std::map< KIID_PATH, std::map< wxString, wxString > > m_dataStore
The rest of the generic fields data model stuff, primarily around row functionality.
void RevertRow(int aRow) override
Go through and revert all the fields in the row to their live values from the item (symbol/footprint/...
virtual wxString getItemIdentifier(const ITEM_TYPE &aItem) const =0
std::vector< ITEM_TYPE > GetRowReferences(int aRow) const
bool groupMatch(const ITEM_TYPE &lhItem, const ITEM_TYPE &rhItem)
void ensureStoredFieldPresent(const ITEM_TYPE &aItem, const wxString &aFieldName)
Makes sure a field is at least marked present-but-empty without changing its value if it has one alre...
void ExpandCollapseRow(int aRow) override
virtual std::vector< ITEM_TYPE > getAllItems() const =0
wxString GetExportValue(int aRow, int aCol, const wxString &refDelimiter, const wxString &refRangeDelimiter) override
void setStoredFieldValue(const ITEM_TYPE &aItem, const wxString &aFieldName, const wxString &aValue)
Creates or updates a field in the data store.
bool fieldIsModified(const ITEM_TYPE &aItem, const wxString &aFieldName)
Compares the live value of the field to the stored value in the data store.
const std::map< wxString, wxString > & getStoredFields(const ITEM_TYPE &aItem) const
Returns all stored fields for an item without creating a data-store entry.
void initializeDataStoreItemField(const ITEM_TYPE &aItem, const DATA_MODEL_COL &aCol)
Puts the live value of the field in the data store, correctly handling a missing field in the souce i...
void initializeDataStoreItem(const ITEM_TYPE &aItem)
Initializes every column in the data store for a newly added (or refreshed) item.
void clearStoredField(const ITEM_TYPE &aItem, const wxString &aFieldName)
Clears a field, e.g.
virtual bool unitMatch(const ITEM_TYPE &lhItem, const ITEM_TYPE &rhItem)=0
bool cmpRows(const DATA_MODEL_ROW< ITEM_TYPE > &lhRow, const DATA_MODEL_ROW< ITEM_TYPE > &rhRow, int aSortCol, bool aAscending)
bool getStoredFieldValue(const ITEM_TYPE &aItem, const wxString &aFieldName, wxString &aValue) const
Gets the stored value of the field from the data store, not from the live item, e....
virtual bool getLiveFieldValue(const ITEM_TYPE &aItem, const wxString &aFieldName, wxString &aValue)=0
Gets the current value of the field from the live item, e.g.
bool IsCellEdited(int aRow, int aCol) override
Returns true if the cell has been modified from the live value in any item in the row (symbol/footpri...
std::vector< DATA_MODEL_ROW< ITEM_TYPE > > m_rows
bool IsCellReadOnly(int aRow, int aCol) override
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser) override
wxString GetValue(int aRow, int aCol) override
std::vector< KIID_PATH > GetRowItemKeys(int aRow) const override
Return the stable data-store keys of every item represented by a row.
bool MatchesFilter(const ITEM_TYPE &aItem, const wxString &aReference, EDA_COMBINED_MATCHER &aMatcher)
bool IsCellClear(int aRow, int aCol) override
Returns true if the cell is not present in the data store for any item in the row,...
bool allRowItemsHaveAttributeForcedOnBySheet(const DATA_MODEL_ROW< ITEM_TYPE > &aRow, int aCol)
wxString GetGroupedValue(const DATA_MODEL_ROW< ITEM_TYPE > &aRow, int aCol, const wxString &refDelimiter=wxT(", "), const wxString &refRangeDelimiter=wxT("-"), bool resolveVars=false, bool listMixedValues=false)
void updateDataStoreItemFieldFromLive(const ITEM_TYPE &aItem, const wxString &aFieldName)
Updates the data store with the current value of the field from the live item.
void CollapseRow(int aRow)
virtual KIID_PATH getDataStoreKey(const ITEM_TYPE &aItem) const =0
void ClearCell(int aRow, int aCol) override
Clears the field from the data store, rather than setting its value to an empty string.
ROW_STATE GetRowState(int aRow) const override
virtual bool attributeForcedOnBySheet(const ITEM_TYPE &aItem, const wxString &aAttributeName) const
Sheets can force all the symbols in them to have certain attributes on, like DNP.
wxString GetResolvedValue(int aRow, int aCol) override
virtual wxString getFieldResolvedLiveValue(const ITEM_TYPE &aItem, const wxString &aFieldName)=0
Explicitly bypasses the data store's field values and retries them from the item's current field valu...
virtual wxString resolveTextVars(const ITEM_TYPE &aItem, const wxString &aText)=0
virtual bool cmpRowItems(const ITEM_TYPE &lhItem, const ITEM_TYPE &rhItem)
int GetNumberRows() override
GRID_CELL_RESOLVED_TEXT_RENDERER()
wxSize GetBestSize(wxGrid &aGrid, wxGridCellAttr &aAttr, wxDC &aDC, int aRow, int aCol) override
wxGridCellRenderer * Clone() const override
void Draw(wxGrid &aGrid, wxGridCellAttr &aAttr, wxDC &aDC, const wxRect &aRect, int aRow, int aCol, bool isSelected) override
bool IsGeneratedValue(const wxString &aValue)
Returns true if some of the string is generated, e.g contains a text var or expression.
Abstract pattern-matching tool and implementations.
const wxColour VARIANT_FIELD_OVERRIDE_DARK_YELLOW(80, 80, 40)
const wxColour VARIANT_FIELD_OVERRIDE_LIGHT_YELLOW(255, 255, 200)
const wxColour STRIPED_CLEARED_EMPTY_FIELD_LIGHT_GREEN(180, 220, 180)
const wxColour TEXT_VARIABLE_DARK_AMBER(80, 70, 30)
const wxColour CLEARED_FIELD_STRIPE_ON_DARK_LIGHT_RED(220, 180, 180)
const wxColour VARIANT_SYMBOL_OVERRIDE_LIGHT_BLUE(220, 235, 255)
const wxColour STRIPED_EDITED_EMPTY_FIELD_MUTED_GREEN(180, 200, 180)
const wxColour EDITED_EMPTY_FIELD_BRIGHT_GREEN(192, 255, 192)
const wxColour TEXT_VARIABLE_LIGHT_YELLOW(255, 252, 200)
const wxColour VARIANT_SYMBOL_OVERRIDE_DARK_BLUE(40, 60, 80)
const wxColour STRIPED_EDITED_NONEMPTY_FIELD_MUTED_RED(200, 180, 180)
const wxColour STRIPED_CLEARED_NONEMPTY_FIELD_LIGHT_RED(220, 180, 180)
const wxColour CLEARED_FIELD_STRIPE_ON_LIGHT_DARK_RED(100, 10, 10)
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
wxString FormatRefDesRanges(const std::vector< wxString > &aReferences, const wxString &aRefDelimiter, const wxString &aRefRangeDelimiter)
Format a sorted list of reference designators, shortening consecutive sequences of three or more refe...
Collection of utility functions for component reference designators (refdes)
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
int ValueStringCompare(const wxString &strFWord, const wxString &strSWord)
Compare strings like the strcmp function but handle numbers and modifiers within the string text corr...
The point of the data model classes is fundamentally to represent three things:
std::vector< LIB_SYMBOL * > m_items
DATA_MODEL_ROW(const ITEM_TYPE &aFirstItem, ROW_STATE aGroupingState)
Functions to provide common constants and other functions to assist in making a consistent UI.
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
enum KICOMMON_API ROW_STATE
Used primarily by the fields tables to collapse multiple grouped symbols, etc.