28#include <nlohmann/json.hpp>
32#include <wx/settings.h>
36 wxGridCellStringRenderer()
42 int aRow,
int aCol,
bool isSelected )
44 wxString value = aGrid.GetCellValue( aRow, aCol );
47 value =
model->GetResolvedValue( aRow, aCol );
52 wxGridCellRenderer::Draw( aGrid, aAttr, aDC, aRect, aRow, aCol, isSelected );
53 SetTextColoursAndFont( aGrid, aAttr, aDC, isSelected );
54 aGrid.DrawTextRectangle( aDC, value, rect, wxALIGN_LEFT, wxALIGN_CENTRE );
61 wxString value = aGrid.GetCellValue( aRow, aCol );
64 value =
model->GetResolvedValue( aRow, aCol );
66 return wxGridCellStringRenderer::DoGetBestSize( aAttr, aDC, value );
104 wxCHECK( aRow >= 0 && aRow < GetNumberRows(),
false );
114 wxCHECK_RET( aAttr, wxS(
"Cannot apply a renderer to a null cell attribute" ) );
124 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
125 bool isDark = ( bg.Red() + bg.Green() + bg.Blue() ) < 384;
135 wxCHECK( aRow >= 0 && aRow < GetNumberRows(),
false );
140 if( datasheetCol < 0 )
143 auto attrIt =
m_colAttrs.find( datasheetCol );
145 if( attrIt ==
m_colAttrs.end() || !attrIt->second )
148 return aCol == datasheetCol ||
IsURL( GetValue( aRow, aCol ) );
155 wxCHECK( datasheetCol >= 0,
nullptr );
157 auto attrIt =
m_colAttrs.find( datasheetCol );
158 wxCHECK( attrIt !=
m_colAttrs.end() && attrIt->second,
nullptr );
160 return attrIt->second->Clone();
169 wxGridCellAttr* stripedAttr = aAttr ? aAttr->Clone() :
new wxGridCellAttr;
170 wxSafeDecRef( aAttr );
181 if( !stripedAttr->HasBackgroundColour() )
182 stripedAttr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
190 constexpr double ROW_HINT_OPACITY = 0.1;
191 constexpr double COLUMN_HINT_OPACITY = 0.05;
197 if( !
grid || !
grid->IsCursorRowColumnHighlightEnabled()
198 || ( aRow !=
grid->GetGridCursorRow() && aCol !=
grid->GetGridCursorCol() ) )
203 wxColour background = aAttr && aAttr->HasBackgroundColour() ? aAttr->GetBackgroundColour()
204 :
grid->GetDefaultCellBackgroundColour();
205 wxColour highlight = wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT );
206 double hintOpacity = aRow ==
grid->GetGridCursorRow() ? ROW_HINT_OPACITY : COLUMN_HINT_OPACITY;
208 wxColour hintedBackground( wxColour::AlphaBlend( highlight.Red(), background.Red(), hintOpacity ),
209 wxColour::AlphaBlend( highlight.Green(), background.Green(), hintOpacity ),
210 wxColour::AlphaBlend( highlight.Blue(), background.Blue(), hintOpacity ) );
212 wxGridCellAttr* hintedAttr = aAttr ? aAttr->Clone() :
new wxGridCellAttr;
213 wxSafeDecRef( aAttr );
214 hintedAttr->SetBackgroundColour( hintedBackground );
222 if( wxGrid*
grid = GetView() )
223 static_cast<WX_GRID*
>(
grid )->CommitPendingChanges(
true );
229 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
230 wxCHECK_RET( aNewPos >= 0 && aNewPos <
static_cast<int>(
m_cols.size() ),
"Invalid New Column Position" );
232 if( aCol == aNewPos )
246 std::rotate( std::begin(
m_cols ) + aCol, std::begin(
m_cols ) + aCol + 1, std::begin(
m_cols ) + aNewPos + 1 );
255 std::rotate( std::begin(
m_cols ) + aNewPos, std::begin(
m_cols ) + aCol, std::begin(
m_cols ) + aCol + 1 );
262 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
271 for(
auto& [variant, state] : field.
m_variants )
272 state.m_value = state.m_baseline;
284 wxSafeDecRef( attrIt->second );
288 std::map<int, wxGridCellAttr*> shiftedColAttrs;
291 shiftedColAttrs[col > aCol ? col - 1 : col] = attr;
295 if( wxGrid*
grid = GetView() )
297 wxGridTableMessage msg(
this, wxGRIDTABLE_NOTIFY_COLS_DELETED, aCol, 1 );
298 grid->ProcessTableMessage( msg );
307 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
311 const wxString oldName =
m_cols[aCol].m_fieldName;
317 auto fieldIt = fieldsStore.find( oldName );
319 if( fieldIt == fieldsStore.end() )
329 for(
const auto& [variant, state] : oldField.
m_variants )
331 newField.
m_variants[variant].m_value = willBeComputed ? newName : wasComputed ? wxString() : state.m_value;
337 m_cols[aCol].m_fieldName = newName;
344 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
346 m_cols[aCol].m_label = aLabel;
353 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ), wxString() );
354 return m_cols[aCol].m_label;
360 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ), wxString() );
361 return m_cols[aCol].m_fieldName;
369 for(
int row = 0; row < GetNumberRows(); ++row )
378 for(
size_t i = 0; i <
m_cols.size(); i++ )
381 return static_cast<int>( i );
390 std::vector<BOM_FIELD> fields;
393 fields.push_back( { col.m_fieldName, col.m_label, col.m_show, col.m_group } );
403 size_t foundCount = 0;
405 for(
const wxString& newField : aNewOrder )
407 if( foundCount >=
m_cols.size() )
412 if( col.m_fieldName == newField )
414 std::swap(
m_cols[foundCount], col );
425 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
432 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
439 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
446 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
453 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
460 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
468 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
476 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
484 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
true );
492 wxCHECK( aRow >= 0 && aRow < GetNumberRows(),
true );
507 wxCHECK( aRow >= 0 && aRow < GetNumberRows(),
false );
508 wxCHECK( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false );
531 wxCHECK( aRow >= 0 && aRow < GetNumberRows(),
false );
545 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
565 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
570 m_cols[aCol].m_group = aGroup;
576 wxCHECK_MSG( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false,
"Invalid Column Number" );
577 return m_cols[aCol].m_group;
583 wxCHECK_RET( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
"Invalid Column Number" );
584 m_cols[aCol].m_show = aShow;
590 wxCHECK_MSG( aCol >= 0 && aCol <
static_cast<int>(
m_cols.size() ),
false,
"Invalid Column Number" );
591 return m_cols[aCol].m_show;
598 for(
size_t i = 0; i <
m_cols.size(); i++ )
604 std::set<wxString> seen;
605 std::vector<wxString> order;
608 for(
const BOM_FIELD& field : aPreset.fieldsOrdered )
611 if( !field.
name || seen.count( field.
name ) )
614 seen.insert( field.
name );
615 order.emplace_back( field.
name );
666 current.readOnly =
false;
693 for(
size_t col = 0; col <
m_cols.size(); col++ )
696 lastCol =
static_cast<int>( col );
704 out.Append( wxString::FromUTF8(
"\xEF\xBB\xBF" ) );
706 auto formatField = [&]( wxString aField,
bool aLast ) -> wxString
710 aField.Replace( wxS(
"\r" ), wxS(
"" ) );
711 aField.Replace( wxS(
"\n" ), wxS(
"" ) );
715 aField.Replace( wxS(
"\t" ), wxS(
"" ) );
727 for(
size_t col = 0; col <
m_cols.size(); col++ )
732 out.Append( formatField(
m_cols[col].m_label, col ==
static_cast<size_t>( lastCol ) ) );
736 for(
int row = 0; row < GetNumberRows(); row++ )
739 if(
GetRowState( row ) == ROW_STATE::EXPANDED_CHILD )
742 for(
size_t col = 0; col <
m_cols.size(); col++ )
747 out.Append( formatField(
749 col ==
static_cast<size_t>( lastCol ) ) );
759 return aFieldName == wxS(
"${DNP}" ) || aFieldName == wxS(
"${EXCLUDE_FROM_BOARD}" )
760 || aFieldName == wxS(
"${EXCLUDE_FROM_BOM}" ) || aFieldName == wxS(
"${EXCLUDE_FROM_POS_FILES}" )
761 || aFieldName == wxS(
"${EXCLUDE_FROM_SIM}" );
774 return wxEmptyString;
776 if( aFieldName == wxS(
"${DNP}" ) )
778 else if( aFieldName == wxS(
"${EXCLUDE_FROM_BOARD}" ) )
779 return wxS(
"Excluded from board" );
780 else if( aFieldName == wxS(
"${EXCLUDE_FROM_BOM}" ) )
781 return wxS(
"Excluded from BOM" );
782 else if( aFieldName == wxS(
"${EXCLUDE_FROM_POS_FILES}" ) )
783 return wxS(
"Excluded from position files" );
784 else if( aFieldName == wxS(
"${EXCLUDE_FROM_SIM}" ) )
785 return wxS(
"Excluded from simulation" );
787 return wxEmptyString;
803 for(
const auto& [
name, field] : fields )
805 if( field.m_present != field.m_baselinePresent )
811 if( field.m_present )
813 for(
const auto& [variant, state] : field.m_variants )
815 if( state.m_value != state.m_baseline )
833 for(
auto& [
name, field] : fields )
835 if(
auto it = field.m_variants.find( aOldName ); it != field.m_variants.end() )
837 field.m_variants[aNewName] = it->second;
838 field.m_variants.erase( it );
854 for(
auto& [
name, field] : fields )
855 field.m_variants.erase( aName );
866 nlohmann::json j = nlohmann::json::object();
870 nlohmann::json jfields = nlohmann::json::object();
872 for(
const auto& [
name, field] : fields )
874 auto& stored = jfields[std::string(
name.ToUTF8() )];
875 stored[
"present"] = field.m_present;
876 stored[
"baseline_present"] = field.m_baselinePresent;
877 stored[
"variants"] = nlohmann::json::object();
879 for(
const auto& [variant, state] : field.m_variants )
881 stored[
"variants"][std::string( variant.ToUTF8() )] = { std::string( state.m_value.ToUTF8() ),
882 std::string( state.m_baseline.ToUTF8() ) };
886 j[std::string( key.AsString().ToUTF8() )] = jfields;
889 return wxString( j.dump() );
895 nlohmann::json j = nlohmann::json::parse( aState.ToStdString(),
nullptr,
false );
904 for(
auto it = j.begin(); it != j.end(); ++it )
906 KIID_PATH key( wxString::FromUTF8( it.key().c_str() ) );
909 for(
auto fit = it.value().begin(); fit != it.value().end(); ++fit )
912 field.
m_present = fit.value().at(
"present" ).get<
bool>();
915 for(
const auto& [variant, state] : fit.value().at(
"variants" ).items() )
917 field.
m_variants[wxString::FromUTF8( variant )] = {
918 wxString::FromUTF8( state.at( 0 ).get<std::string>() ),
919 wxString::FromUTF8( state.at( 1 ).get<std::string>() )
929 GetView()->ForceRefresh();
Contains everything completly generic to fields tables data models, as well as column functionality t...
bool cellUsesResolvedTextRenderer(int aRow, int aCol)
virtual bool fieldIsItemProperty(const wxString &aFieldName) const
void DeleteStoredVariant(const wxString &aName)
bool cellUsesUrlEditor(int aRow, int aCol)
~FIELDS_TABLE_DATA_MODEL_BASE() override
FIELDS_TABLE_DATA_MODEL_BASE()
virtual void SetCurrentVariant(const wxString &aVariantName)=0
Select the displayed variant, retaining un-applied edits in every variant.
BOM_FILTER_SCOPE GetFilterScope() const
virtual bool IsCellEdited(int aRow, int aCol)=0
void SetExcludeDNP(bool aExclude)
std::map< KIID_PATH, std::map< wxString, FIELD_STORE_VALUE > > m_dataStore
bool ColIsComputed(int aCol) const
void SetSorting(int aCol, bool aAscending)
int GetNumberCols() override
void MoveColumn(int aCol, int aNewPos)
wxString GetColFieldName(int aCol)
bool ColIsValue(int aCol) const
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 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 SetFieldsOrder(const std::vector< wxString > &aNewOrder)
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)
wxString fieldVariant(const wxString &aFieldName, const wxString &aVariantName) const
bool GetIncludeExcludedFromBOM()
wxString SerializeUndoState() const override
void SetGroupingEnabled(bool aGroup)
int GetColDataWidth(int aCol)
bool ColIsItemNumber(int aCol) const
const wxString & GetFilter()
virtual bool fieldSupportsVariants(const wxString &aFieldName) const
wxGridCellRenderer * m_stripedRenderer
std::vector< DATA_MODEL_COL > m_cols
bool GetGroupingEnabled()
bool CanCopyCellFromVariant(int aRow, int aCol)
void RenameStoredVariant(const wxString &aOldName, const wxString &aNewName)
void RestoreUndoState(const wxString &aState) override
void RenameColumn(int aCol, const wxString &newName)
void SetGroupColumn(int aCol, bool aGroup)
void SetFilter(const wxString &aFilter)
wxString GetColLabelValue(int aCol) override
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.
Cell renderer that shows the expanded result of text variables (e.g.
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
virtual ROW_STATE GetRowState(int aRow) const
std::map< int, wxGridCellAttr * > m_colAttrs
void FinalizeTextVarExpansion(wxString &aText, RESOLUTION_CONTEXT aContext)
bool IsGeneratedValue(const wxString &aValue)
Returns true if some of the string is generated, e.g contains a text var or expression.
bool IsGeneratedField(const wxString &aFieldName)
Returns true if the entire string is generated, e.g is a single text var reference.
STRIPED_CELL_RENDERER< wxGridCellStringRenderer > STRIPED_STRING_RENDERER
const wxColour TEXT_VARIABLE_DARK_AMBER(80, 70, 30)
const wxColour CLEARED_FIELD_STRIPE_ON_DARK_LIGHT_RED(220, 180, 180)
const wxColour TEXT_VARIABLE_LIGHT_YELLOW(255, 252, 200)
const wxColour CLEARED_FIELD_STRIPE_ON_LIGHT_DARK_RED(100, 10, 10)
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 IsURL(wxString aStr)
Performs a URL sniff-test on a string.
bool includeByteOrderMark
wxString refRangeDelimiter
The point of the data model classes is fundamentally to represent three things:
std::map< wxString, FIELD_VALUE_STATE > m_variants
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...
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
Functions to provide common constants and other functions to assist in making a consistent UI.