KiCad PCB EDA Suite
Loading...
Searching...
No Matches
lib_fields_data_model.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19#include <wx/string.h>
20#include <wx/debug.h>
21#include <wx/grid.h>
22#include <wx/settings.h>
23#include <wx/brush.h>
24#include <common.h>
25#include <widgets/wx_grid.h>
26#include <sch_reference_list.h>
27#include <schematic_settings.h>
28#include <template_fieldnames.h>
29#include "string_utils.h"
30#include <trace_helpers.h>
31#include <validators.h>
32
34
35
36const wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME = wxS( "${SYMBOL_NAME}" );
37const wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_KEYWORDS = wxS( "${SYMBOL_KEYWORDS}" );
38const wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_POWER = wxS( "${SYMBOL_IS_POWER}" );
39const wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_IS_LOCAL_POWER = wxS( "${SYMBOL_IS_LOCAL_POWER}" );
40
41
43 const wxString& aFieldName,
44 wxString& aValue )
45{
46 int col = GetFieldNameCol( aFieldName );
47 aValue.clear();
48
49 if( col != -1 && ColIsAttribute( col ) )
50 {
51 aValue = getAttributeValue( aSymbol, aFieldName );
52 return true;
53 }
54 else if( const SCH_FIELD* field = aSymbol->GetField( aFieldName ) )
55 {
56 aValue = field->GetText();
57 return true;
58 }
59 else if( aFieldName == SYMBOL_KEYWORDS )
60 {
61 aValue = aSymbol->GetKeyWords();
62 return true;
63 }
64 else if( aFieldName == SYMBOL_NAME )
65 {
66 aValue = aSymbol->GetName();
67 return true;
68 }
69
70 return false;
71}
72
73
74std::vector<LIB_SYMBOL*> LIB_FIELDS_EDITOR_GRID_DATA_MODEL::getAllItems() const
75{
76 return m_symbolsList;
77}
78
79
80void LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString& aValue )
81{
82 wxCHECK_RET( aRow >= 0 && aRow < (int) m_rows.size(), wxS( "Invalid row number" ) );
83 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), wxS( "Invalid column number" ) );
84
85 if( IsCellReadOnly( aRow, aCol ) )
86 return;
87
88 if( aValue == INDETERMINATE_STATE )
89 return;
90
92 const wxString& fieldName = m_cols[aCol].m_fieldName;
93
94 for( LIB_SYMBOL* symbol : rowGroup.m_items )
95 {
96 if( fieldName == SYMBOL_IS_POWER )
97 {
98 setStoredFieldValue( symbol, fieldName, aValue );
99
100 if( aValue == wxS( "1" ) )
101 setPowerSymbolDefaults( symbol );
102 }
103 else if( fieldName == SYMBOL_IS_LOCAL_POWER )
104 {
105 // Local Power is disabled in the symbol properties dialog until Power is enabled.
106 if( getStoredPowerSymbolValue( symbol ) )
107 {
108 setStoredFieldValue( symbol, fieldName, aValue );
109 setPowerSymbolDefaults( symbol );
110 }
111 }
112 else if( getStoredPowerSymbolValue( symbol ) && isPowerSymbolControlledField( fieldName ) )
113 {
114 if( fieldName == GetDefaultFieldName( FIELD_T::VALUE, UNTRANSLATED ) )
115 setStoredFieldValue( symbol, fieldName, symbol->GetName() );
116 else
117 setStoredFieldValue( symbol, fieldName, wxS( "1" ) );
118 }
119 else
120 {
121 setStoredFieldValue( symbol, fieldName, aValue );
122 }
123 }
124
125 m_edited = true;
126}
127
128
130{
131 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
132 return m_cols[aCol].m_fieldName == LIB_FIELDS_EDITOR_GRID_DATA_MODEL::SYMBOL_NAME;
133}
134
135
136bool LIB_FIELDS_EDITOR_GRID_DATA_MODEL::fieldIsAttribute( const wxString& aFieldName ) const
137{
138 return FIELDS_TABLE_DATA_MODEL_BASE::fieldIsAttribute( aFieldName ) || aFieldName == SYMBOL_IS_POWER
139 || aFieldName == SYMBOL_IS_LOCAL_POWER;
140}
141
142
143bool LIB_FIELDS_EDITOR_GRID_DATA_MODEL::fieldIsItemProperty( const wxString& aFieldName ) const
144{
145 return aFieldName == SYMBOL_NAME || aFieldName == SYMBOL_KEYWORDS
147}
148
149
151{
153 return true;
154
155 if( m_cols[aCol].m_fieldName == SYMBOL_IS_LOCAL_POWER )
156 {
157 for( LIB_SYMBOL* symbol : m_rows[aRow].m_items )
158 {
159 if( getStoredPowerSymbolValue( symbol ) )
160 return false;
161 }
162
163 return true;
164 }
165
166 if( !isPowerSymbolControlledField( m_cols[aCol].m_fieldName ) )
167 return false;
168
169 for( LIB_SYMBOL* symbol : m_rows[aRow].m_items )
170 {
171 if( !getStoredPowerSymbolValue( symbol ) )
172 return false;
173 }
174
175 return true;
176}
177
178
179wxGridCellAttr* LIB_FIELDS_EDITOR_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
180{
181 wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
182 bool needsUrlEditor = cellUsesUrlEditor( aRow, aCol );
183 bool needsResolvedTextRenderer = cellUsesResolvedTextRenderer( aRow, aCol );
184
185 wxGridCellAttr* modelAttr = nullptr;
186
187 if( needsUrlEditor )
188 modelAttr = cloneUrlEditorAttr();
189 else if( m_colAttrs.find( aCol ) != m_colAttrs.end() && m_colAttrs[aCol] )
190 modelAttr = m_colAttrs[aCol]->Clone();
191
192 if( modelAttr )
193 {
194 if( attr )
195 {
196 // Copy any existing attributes that aren't overridden
197 if( attr->HasBackgroundColour() && !modelAttr->HasBackgroundColour() )
198 modelAttr->SetBackgroundColour( attr->GetBackgroundColour() );
199 if( attr->HasTextColour() && !modelAttr->HasTextColour() )
200 modelAttr->SetTextColour( attr->GetTextColour() );
201 if( attr->HasFont() && !modelAttr->HasFont() )
202 modelAttr->SetFont( attr->GetFont() );
203
204 attr->DecRef();
205 }
206
207 attr = modelAttr;
208 }
209 else if( !attr )
210 {
211 attr = new wxGridCellAttr;
212 }
213
214 if( IsCellReadOnly( aRow, aCol ) )
215 attr->SetReadOnly();
216
217 bool rowModified = false;
218 bool cellModified = false;
219 bool cellEmpty = true;
220 bool blankModified = false;
221
222 const wxString& fieldName = m_cols[aCol].m_fieldName;
223
224 for( LIB_SYMBOL* symbol : m_rows[aRow].m_items )
225 {
226 wxString liveValue;
227 wxString storedValue;
228 bool liveFieldPresent = getLiveFieldValue( symbol, fieldName, liveValue );
229 bool storedFieldPresent = getStoredFieldValue( symbol, fieldName, storedValue );
230 bool modified = liveFieldPresent != storedFieldPresent || liveValue != storedValue;
231
232 if( modified )
233 cellModified = true;
234
235 bool elementEmpty = !storedFieldPresent || ( !liveFieldPresent && !modified );
236
237 if( !elementEmpty )
238 cellEmpty = false;
239
240 if( storedValue.IsEmpty() && modified )
241 blankModified = true;
242
243 if( !rowModified )
244 {
245 for( const DATA_MODEL_COL& col : m_cols )
246 {
247 if( fieldIsModified( symbol, col.m_fieldName ) )
248 {
249 rowModified = true;
250 break;
251 }
252 }
253 }
254
255 if( cellModified && rowModified && !cellEmpty )
256 break;
257 }
258
259 if( cellEmpty && !ColIsAttribute( aCol ) )
260 {
261 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
262
263 for( LIB_SYMBOL* symbol : m_rows[aRow].m_items )
264 {
265 wxString liveValue;
266 wxString storedValue;
267 bool liveFieldPresent = getLiveFieldValue( symbol, fieldName, liveValue );
268 bool storedFieldPresent = getStoredFieldValue( symbol, fieldName, storedValue );
269 bool modified = liveFieldPresent != storedFieldPresent || liveValue != storedValue;
270
271 if( modified )
272 {
273 if( !storedFieldPresent )
274 {
275 if( !liveFieldPresent )
276 {
277 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
278 }
279 else if( liveValue.empty() )
280 {
282 }
283 else
284 {
286 }
287 }
288 else if( storedValue.IsEmpty() )
289 {
291 }
292 else
293 {
295 }
296 }
297 }
298 }
299 else
300 {
301 if( rowModified )
302 attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
303
304 if( blankModified )
305 attr->SetBackgroundColour( FIELDS_TABLE_COLOR::EDITED_EMPTY_FIELD_BRIGHT_GREEN );
306 }
307
308 if( needsResolvedTextRenderer )
309 applyResolvedTextRenderer( attr, !rowModified );
310
311 if( cellModified )
312 {
313 wxFont font;
314
315 if( attr->HasFont() )
316 font = attr->GetFont();
317 else if( GetView() )
318 font = GetView()->GetDefaultCellFont();
319 else
320 font = wxFont();
321
322 if( font.IsOk() )
323 {
324 font.MakeBold();
325 attr->SetFont( font );
326 }
327 }
328
329 return applyCellDecorations( attr, aRow, aCol );
330}
331
332
334 wxString& aNewSymbolName )
335{
336 wxCHECK_RET( aRow >= 0 && aRow < (int) m_rows.size(), "Invalid Row Number" );
337 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
338
339 const LIB_SYMBOL* parentSymbol = m_rows[aRow].m_items[0];
340
341 wxLogTrace( traceLibFieldTable, "CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
342 aNewSymbolName, parentSymbol->GetName() );
343
344 // Generate a fresh UUID for the new derived symbol
345 KIID newDerivedSymbolUuid;
346
347 // Create the symbol immediately
348 createActualDerivedSymbol( parentSymbol, aNewSymbolName, newDerivedSymbolUuid );
349
350 // Rebuild the grid to show the new symbol
351 RebuildRows();
352
353 m_edited = true;
354}
355
356void LIB_FIELDS_EDITOR_GRID_DATA_MODEL::createActualDerivedSymbol( const LIB_SYMBOL* aParentSymbol, const wxString& aNewSymbolName, const KIID& aNewSymbolUuid )
357{
358 wxLogTrace( traceLibFieldTable, "createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
359 aNewSymbolName, aParentSymbol->GetName(), m_symbolsList.size() );
360
361 LIB_SYMBOL* newSymbol = nullptr;
362
363 for( LIB_SYMBOL* sym : m_symbolsList )
364 {
365 if( sym->m_Uuid == aNewSymbolUuid )
366 {
367 newSymbol = sym;
368 break;
369 }
370 }
371
372 if( !newSymbol )
373 {
374 newSymbol = new LIB_SYMBOL( *aParentSymbol );
375 newSymbol->SetName( aNewSymbolName );
376
377 // Also update the VALUE field to reflect the new name for derived symbols
378 newSymbol->GetValueField().SetText( aNewSymbolName );
379
380 newSymbol->SetParent( const_cast<LIB_SYMBOL*>( aParentSymbol ) );
381 // Note: SetLib() not called here - library association handled by dialog's library manager
382 const_cast<KIID&>( newSymbol->m_Uuid ) = aNewSymbolUuid;
383 m_symbolsList.push_back( newSymbol );
384
385 wxLogTrace( traceLibFieldTable, "createActualDerivedSymbol: Added new symbol to list, size now: %zu",
386 m_symbolsList.size() );
387
388 // Initialize field data for the new symbol in the data store
389 initializeDataStoreItem( newSymbol );
390
391 wxLogTrace( traceLibFieldTable, "createActualDerivedSymbol: Initialized field data for new symbol" );
392 }
393
394 // Note: Not adding to symbolLibrary directly - this will be handled by the dialog's library manager integration
395 wxString libraryName = aParentSymbol->GetLibId().GetLibNickname();
396 m_createdDerivedSymbols.emplace_back( newSymbol, libraryName );
397
398 wxLogTrace( traceLibFieldTable, "Created derived symbol '%s' for library '%s', total tracked: %zu",
399 aNewSymbolName, libraryName, m_createdDerivedSymbols.size() );
400}
401
403 const wxString& aAttributeName )
404{
405 if( aAttributeName == wxS( "${DNP}" ) )
406 return aSymbol->GetDNP() ? wxS( "1" ) : wxS( "0" );
407
408 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
409 return aSymbol->GetExcludedFromBoard() ? wxS( "1" ) : wxS( "0" );
410
411 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
412 return aSymbol->GetExcludedFromBOM() ? wxS( "1" ) : wxS( "0" );
413
414 if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
415 return aSymbol->GetExcludedFromSim() ? wxS( "1" ) : wxS( "0" );
416
417 if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
418 return aSymbol->GetExcludedFromPosFiles() ? wxS( "1" ) : wxS( "0" );
419
420 if( aAttributeName == SYMBOL_IS_POWER )
421 return aSymbol->IsPower() ? wxS( "1" ) : wxS( "0" );
422
423 if( aAttributeName == SYMBOL_IS_LOCAL_POWER )
424 return aSymbol->IsLocalPower() ? wxS( "1" ) : wxS( "0" );
425
426
427 return wxS( "0" );
428}
429
431 const wxString& aAttributeName,
432 const wxString& aValue )
433{
434 if( aAttributeName == wxS( "${DNP}" ) )
435 aSymbol->SetDNP( aValue == wxS( "1" ) );
436 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
437 aSymbol->SetExcludedFromBoard( aValue == wxS( "1" ) );
438 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
439 aSymbol->SetExcludedFromBOM( aValue == wxS( "1" ) );
440 else if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
441 aSymbol->SetExcludedFromSim( aValue == wxS( "1" ) );
442 else if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
443 aSymbol->SetExcludedFromPosFiles( aValue == wxS( "1" ) );
444 else
445 wxLogDebug( "Unknown attribute name: %s", aAttributeName );
446}
447
448
450{
451 return aFieldName == GetDefaultFieldName( FIELD_T::VALUE, UNTRANSLATED )
452 || aFieldName == wxS( "${EXCLUDE_FROM_BOARD}" )
453 || aFieldName == wxS( "${EXCLUDE_FROM_BOM}" )
454 || aFieldName == wxS( "${EXCLUDE_FROM_POS_FILES}" )
455 || aFieldName == wxS( "${EXCLUDE_FROM_SIM}" );
456}
457
458
460{
461 wxString value;
462
463 if( getStoredFieldValue( aSymbol, SYMBOL_IS_POWER, value ) )
464 return value == wxS( "1" );
465
466 return GetFieldNameCol( SYMBOL_IS_POWER ) == -1 && aSymbol->IsPower();
467}
468
469
471{
473
474 static const std::vector<wxString> exclusionFields = {
475 wxS( "${EXCLUDE_FROM_BOARD}" ),
476 wxS( "${EXCLUDE_FROM_BOM}" ),
477 wxS( "${EXCLUDE_FROM_POS_FILES}" ),
478 wxS( "${EXCLUDE_FROM_SIM}" ),
479 };
480
481 for( const wxString& fieldName : exclusionFields )
482 {
483 if( GetFieldNameCol( fieldName ) != -1 )
484 setStoredFieldValue( aSymbol, fieldName, wxS( "1" ) );
485 }
486}
487
488
489wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::getAttributeResolvedValue( const wxString& aFieldName, bool aValue ) const
490{
491 if( !aValue )
492 return wxEmptyString;
493
494 if( aFieldName == SYMBOL_IS_POWER )
495 return wxS( "Power Symbol" );
496 else if( aFieldName == SYMBOL_IS_LOCAL_POWER )
497 return wxS( "Local Power Symbol" );
498
500}
501
502
504{
505 if( !m_rebuildsEnabled )
506 return;
507
508 wxLogTrace( traceLibFieldTable, "RebuildRows: Starting rebuild with %zu symbols in list", m_symbolsList.size() );
509
510 if( GetView() )
511 {
512 // Commit any pending in-place edits before the row gets moved out from under
513 // the editor.
514 static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
515
516 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (int) m_rows.size() );
517 GetView()->ProcessTableMessage( msg );
518 }
519
520 m_rows.clear();
521
522 wxLogTrace( traceLibFieldTable, "RebuildRows: About to process %zu symbols", m_symbolsList.size() );
523
524 EDA_COMBINED_MATCHER matcher( m_filter.Lower(), CTX_SEARCH );
525
526 for( LIB_SYMBOL* symbol : m_symbolsList )
527 {
528 wxLogTrace( traceLibFieldTable, "RebuildRows: Processing symbol '%s' (UUID: %s)",
529 symbol->GetName(), symbol->m_Uuid.AsString() );
530
531 if( m_scope == SCOPE::SCOPE_RELATED_SYMBOLS )
532 {
533 std::shared_ptr<LIB_SYMBOL> root = symbol->GetRootSymbol();
534
535 if( !root || root->GetName() != m_relatedSymbolRoot )
536 continue;
537 }
538
539 if( !MatchesFilter( symbol, symbol->GetName(), matcher ) )
540 continue;
541
542 if( m_excludeDNP && symbol->GetDNP() )
543 continue;
544
545 if( !m_includeExcluded && symbol->GetExcludedFromBOM() )
546 continue;
547
548 bool matchFound = false;
549
550 // Performance optimization for ungrouped case to skip the N^2 for loop
551 if( !m_groupingEnabled )
552 {
553 m_rows.emplace_back( LIB_FIELDS_TABLE_DATA_MODEL_ROW( symbol, ROW_STATE::NON_EXPANDABLE ) );
554 continue;
555 }
556
557 // See if we already have a row which this symbol fits into
559 {
560 // all group members must have identical refs so just use the first one
561 LIB_SYMBOL* rowSymbol = row.m_items[0];
562
563 if( groupMatch( symbol, rowSymbol ) )
564 {
565 matchFound = true;
566 row.m_items.push_back( symbol );
567 row.m_state = ROW_STATE::COLLAPSED;
568 break;
569 }
570 }
571
572 if( !matchFound )
573 m_rows.emplace_back( LIB_FIELDS_TABLE_DATA_MODEL_ROW( symbol, ROW_STATE::NON_EXPANDABLE ) );
574 }
575
576 if( GetView() )
577 {
578 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (int) m_rows.size() );
579 GetView()->ProcessTableMessage( msg );
580 }
581
582 wxLogTrace( traceLibFieldTable, "RebuildRows: Completed rebuild with %zu rows created", m_rows.size() );
583 Sort();
584}
585
586
588{
589 return lhItem == rhItem;
590}
591
592
594 const wxString& aFieldName )
595{
596 SCH_FIELD* field = aRef->GetField( aFieldName );
597
598 if( field )
599 {
600 if( field->IsPrivate() )
601 return wxEmptyString;
602 else
603 return field->GetShownText( nullptr, INTERNAL );
604 }
605
606 // Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
607 // the symbol by giving them the correct value by resolving against the symbol
608 if( IsGeneratedField( aFieldName ) )
609 {
610 int depth = 0;
611
612 std::function<bool( wxString* )> libSymbolResolver =
613 [&]( wxString* token ) -> bool
614 {
615 return aRef->ResolveTextVar( token, depth + 1 );
616 };
617
618 return ResolveTextVars( aFieldName, &libSymbolResolver, depth );
619 }
620
621 return wxEmptyString;
622}
623
624
625wxString LIB_FIELDS_EDITOR_GRID_DATA_MODEL::resolveTextVars( LIB_SYMBOL* const& aLibSymbol, const wxString& aText )
626{
627 // TODO: this isn't technically correct, this should resolve against the
628 // data store's copy of variables whenever whenever possible,
629 // but currently it is resolving against the symbol's current values.
630 // For instance, if you have "My value is ${VALUE}" in the description field,
631 // ${VALUE} will be resolved against the symbol's live value, not the Value field
632 // stored in the data store.
633 std::function<bool( wxString* )> libSymbolResolver =
634 [&]( wxString* token ) -> bool
635 {
636 return aLibSymbol->ResolveTextVar( token );
637 };
638
639 int depth = 0;
640 return ResolveTextVars( aText, &libSymbolResolver, depth );
641}
642
643
644void LIB_FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( std::function<void( LIB_SYMBOL* )> symbolChangeHandler,
645 std::function<void()> postApplyHandler )
646{
647 int powerCol = GetFieldNameCol( SYMBOL_IS_POWER );
648 int localPowerCol = GetFieldNameCol( SYMBOL_IS_LOCAL_POWER );
649
650 for( LIB_SYMBOL* symbol : m_symbolsList )
651 {
652 bool symbolModified = false;
653 bool symbolIsPower = symbol->IsPower();
654 bool symbolIsLocalPower = symbol->IsLocalPower();
655 wxString value;
656
657 if( powerCol != -1 )
658 symbolIsPower = getStoredFieldValue( symbol, SYMBOL_IS_POWER, value ) && value == wxS( "1" );
659
660 if( localPowerCol != -1 )
661 {
662 symbolIsLocalPower = getStoredFieldValue( symbol, SYMBOL_IS_LOCAL_POWER, value )
663 && value == wxS( "1" );
664 }
665
666 // Local power is a subtype of power, so apply the two checkbox columns as one
667 // three-state property rather than allowing column order to determine the result.
668 if( powerCol != -1 && !symbolIsPower )
669 symbolIsLocalPower = false;
670 else if( symbolIsLocalPower )
671 symbolIsPower = true;
672
673 if( symbol->IsPower() != symbolIsPower || symbol->IsLocalPower() != symbolIsLocalPower )
674 {
675 if( symbolIsLocalPower )
676 symbol->SetLocalPower();
677 else if( symbolIsPower )
678 symbol->SetGlobalPower();
679 else
680 symbol->SetNormal();
681
682 symbolModified = true;
683 }
684
685 for( size_t i = 0; i < m_cols.size(); ++i )
686 {
687 const DATA_MODEL_COL& col = m_cols[i];
688 const wxString& srcName = col.m_fieldName;
689 wxString srcValue;
690 bool currentlyPresent = getStoredFieldValue( symbol, srcName, srcValue );
691
692 if( srcName == SYMBOL_NAME )
693 continue;
694
695 if( srcName == SYMBOL_IS_POWER || srcName == SYMBOL_IS_LOCAL_POWER )
696 continue;
697
698 // Attributes bypass the field logic, so handle them first
699 if( ColIsAttribute( static_cast<int>( i ) ) )
700 {
701 wxString newValue = currentlyPresent ? srcValue : wxString( wxS( "0" ) );
702
703 if( getAttributeValue( symbol, srcName ) != newValue )
704 {
705 setAttributeValue( symbol, srcName, newValue );
706 symbolModified = true;
707 }
708
709 continue;
710 }
711
712 if( srcName == SYMBOL_KEYWORDS )
713 {
714 if( symbol->GetKeyWords() != srcValue )
715 {
716 symbol->SetKeyWords( srcValue );
717 symbolModified = true;
718 }
719
720 continue;
721 }
722
723 // Skip special fields with variables as names (e.g. ${QUANTITY}),
724 // they can't be edited
725 if( IsGeneratedField( srcName ) )
726 continue;
727
728 SCH_FIELD* destField = symbol->GetField( srcName );
729
730 if( !currentlyPresent && destField )
731 {
732 if( destField->IsMandatory() )
733 {
734 // Value cannot be empty, but the other mandatory fields can be cleared.
735 if( destField->GetId() != FIELD_T::VALUE && !destField->GetText().IsEmpty() )
736 {
737 destField->SetText( wxEmptyString );
738 symbolModified = true;
739 }
740 }
741 else if( !destField->IsPrivate() )
742 {
743 symbol->RemoveField( destField );
744 symbolModified = true;
745 }
746
747 continue;
748 }
749
750 // Every present data-store entry represents a field that should exist,
751 // including entries with an explicitly empty value
752 bool createField = !destField && currentlyPresent;
753
754 if( createField )
755 {
756 const VECTOR2I symbolPos = symbol->GetPosition();
757 destField = new SCH_FIELD( symbol, FIELD_T::USER, srcName );
758 destField->SetPosition( symbolPos );
759 symbol->AddField( destField );
760 symbolModified = true;
761 }
762
763 if( !destField )
764 continue;
765
766 if( destField->GetId() == FIELD_T::VALUE )
767 {
768 // Value field cannot be empty
769 wxString newValue = symbolIsPower ? symbol->GetName() : srcValue;
770
771 if( !newValue.IsEmpty() && destField->GetText() != newValue )
772 {
773 symbol->GetField( FIELD_T::VALUE )->SetText( newValue );
774 symbolModified = true;
775 }
776 }
777 else if( destField->GetText() != srcValue )
778 {
779 destField->SetText( srcValue );
780 symbolModified = true;
781 }
782 }
783
784 std::vector<SCH_FIELD*> symbolFields;
785 symbol->GetFields( symbolFields );
786
787 // Remove any fields that are not mandatory
788 for( SCH_FIELD* field : symbolFields )
789 {
790 if( field->IsMandatory() || field->IsPrivate() )
791 continue;
792
793 const wxString& existingName = field->GetName();
794
795 // Entries for fields whose columns still exist were handled above. Anything left here
796 // has had its column removed from the table.
797 if( GetFieldNameCol( existingName ) == -1 )
798 {
799 symbol->RemoveField( field );
800 symbolModified = true;
801 }
802 }
803
804 if( symbolModified )
805 symbolChangeHandler( symbol );
806
807 for( const DATA_MODEL_COL& col : m_cols )
808 updateDataStoreItemFieldFromLive( symbol, col.m_fieldName );
809 }
810
811 m_edited = false;
812
813 // Call post-apply handler if provided (for library operations and tree refresh)
814 if( postApplyHandler )
815 postApplyHandler();
816}
817
818
819bool LIB_FIELDS_EDITOR_GRID_DATA_MODEL::ValidateReferences( wxString& aSymbolName, wxString& aErrorMessage ) const
820{
821 const wxString referenceFieldName = GetDefaultFieldName( FIELD_T::REFERENCE, UNTRANSLATED );
822
823 for( LIB_SYMBOL* symbol : m_symbolsList )
824 {
825 wxString reference;
826 getStoredFieldValue( symbol, referenceFieldName, reference );
827
828 // An empty reference on a derived symbol inherits the parent's reference.
829 if( symbol->IsDerived() && reference.IsEmpty() )
830 continue;
831
832 aErrorMessage = GetFieldValidationErrorMessage( FIELD_T::REFERENCE, reference );
833
834 if( !aErrorMessage.IsEmpty() )
835 {
836 aSymbolName = UnescapeString( symbol->GetName() );
837 return false;
838 }
839 }
840
841 return true;
842}
843
844
846{
847 if( ColIsAttribute( col ) )
848 return wxGRID_VALUE_BOOL;
849
850 return wxGridTableBase::GetTypeName( row, col );
851}
852
853
855{
856 KIID_PATH key;
857 key.push_back( aItem->m_Uuid );
858 return key;
859}
860
861
863{
864 return aItem->GetName();
865}
const KIID m_Uuid
Definition eda_item.h:597
virtual bool fieldIsItemProperty(const wxString &aFieldName) const
void applyResolvedTextRenderer(wxGridCellAttr *aAttr, bool aApplyTint)
virtual bool fieldIsAttribute(const wxString &aFieldName) const
wxGridCellAttr * applyCellDecorations(wxGridCellAttr *aAttr, int aRow, int aCol)
virtual wxString getAttributeResolvedValue(const wxString &aFieldName, bool aValue) const
int GetFieldNameCol(const wxString &aFieldName) const
bool groupMatch(const LIB_SYMBOL *&lhItem, const LIB_SYMBOL *&rhItem)
void setStoredFieldValue(const LIB_SYMBOL *&aItem, const wxString &aFieldName, const wxString &aValue)
bool fieldIsModified(const LIB_SYMBOL *&aItem, const wxString &aFieldName)
void initializeDataStoreItem(const LIB_SYMBOL *&aItem)
bool getStoredFieldValue(const LIB_SYMBOL *&aItem, const wxString &aFieldName, wxString &aValue) const
std::vector< DATA_MODEL_ROW< LIB_SYMBOL * > > m_rows
bool IsCellReadOnly(int aRow, int aCol) override
bool MatchesFilter(const LIB_SYMBOL *&aItem, const wxString &aReference, EDA_COMBINED_MATCHER &aMatcher)
void updateDataStoreItemFieldFromLive(const LIB_SYMBOL *&aItem, const wxString &aFieldName)
Definition kiid.h:46
bool fieldIsItemProperty(const wxString &aFieldName) const override
void SetValue(int aRow, int aCol, const wxString &aValue) override
wxString getAttributeResolvedValue(const wxString &aFieldName, bool aValue) const override
wxString getAttributeValue(const LIB_SYMBOL *, const wxString &aAttributeName)
std::vector< std::pair< LIB_SYMBOL *, wxString > > m_createdDerivedSymbols
std::vector< LIB_SYMBOL * > getAllItems() const override
bool IsCellReadOnly(int aRow, int aCol) override
KIID_PATH getDataStoreKey(LIB_SYMBOL *const &aItem) const override
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) override
bool ColIsItemIdentifier(int aCol) const override
Reference for symbol/fields tables, lib_id for lib tables.
void CreateDerivedSymbolImmediate(int aRow, int aCol, wxString &aNewSymbolName)
bool getStoredPowerSymbolValue(LIB_SYMBOL *aSymbol) const
wxString getFieldResolvedLiveValue(LIB_SYMBOL *const &aSymbol, const wxString &aFieldName) override
Explicitly bypasses the data store's field values and retries them from the item's current field valu...
void createActualDerivedSymbol(const LIB_SYMBOL *aParentSymbol, const wxString &aNewSymbolName, const KIID &aNewSymbolUuid)
bool fieldIsAttribute(const wxString &aFieldName) const override
void ApplyData(std::function< void(LIB_SYMBOL *)> symbolChangeHandler, std::function< void()> postApplyHandler=nullptr)
std::vector< LIB_SYMBOL * > m_symbolsList
void setAttributeValue(LIB_SYMBOL *aSymbol, const wxString &aAttributeName, const wxString &aValue)
bool unitMatch(LIB_SYMBOL *const &lhItem, LIB_SYMBOL *const &rhItem) override
bool getLiveFieldValue(LIB_SYMBOL *const &aSymbol, const wxString &aFieldName, wxString &aValue) override
Gets the current value of the field from the live item, e.g.
wxString getItemIdentifier(LIB_SYMBOL *const &aItem) const override
wxString GetTypeName(int row, int col) override
bool isPowerSymbolControlledField(const wxString &aFieldName) const
wxString resolveTextVars(LIB_SYMBOL *const &aSymbol, const wxString &aText) override
void setPowerSymbolDefaults(LIB_SYMBOL *aSymbol)
bool ValidateReferences(wxString &aSymbolName, wxString &aErrorMessage) const
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Define a library symbol object.
Definition lib_symbol.h:119
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:188
wxString GetKeyWords() const override
Definition lib_symbol.h:215
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
Definition lib_symbol.h:181
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:437
bool IsLocalPower() const override
virtual void SetName(const wxString &aName)
bool IsMandatory() const
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:138
FIELD_T GetId() const
Definition sch_field.h:142
wxString GetShownText(const SCH_SHEET_PATH *aPath, RESOLUTION_CONTEXT aContext, const wxString &aVariantName=wxEmptyString, int aDepth=0) const
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
bool IsPrivate() const
Definition sch_item.h:253
bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:227
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
Definition symbol.h:206
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
Definition symbol.h:236
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
Definition symbol.h:176
virtual bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:197
virtual void SetDNP(bool aDNP, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Definition symbol.h:238
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:212
void SetExcludedFromPosFiles(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from position files flag.
Definition symbol.h:221
virtual bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition symbol.h:182
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.
Definition symbol.h:191
std::map< int, wxGridCellAttr * > m_colAttrs
Definition wx_grid.h:108
bool IsGeneratedField(const wxString &aFieldName)
Returns true if the entire string is generated, e.g is a single text var reference.
Definition common.cpp:494
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:333
@ INTERNAL
Definition common.h:92
@ CTX_SEARCH
const wxChar *const traceLibFieldTable
DATA_MODEL_ROW< LIB_SYMBOL * > LIB_FIELDS_TABLE_DATA_MODEL_ROW
const wxColour STRIPED_CLEARED_EMPTY_FIELD_LIGHT_GREEN(180, 220, 180)
const wxColour STRIPED_EDITED_EMPTY_FIELD_MUTED_GREEN(180, 200, 180)
const wxColour EDITED_EMPTY_FIELD_BRIGHT_GREEN(192, 255, 192)
const wxColour STRIPED_EDITED_NONEMPTY_FIELD_MUTED_RED(200, 180, 180)
const wxColour STRIPED_CLEARED_NONEMPTY_FIELD_LIGHT_RED(220, 180, 180)
wxString UnescapeString(const wxString &aSource)
The point of the data model classes is fundamentally to represent three things:
std::vector< ITEM_TYPE > m_items
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
wxLogTrace helper definitions.
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46
wxString GetFieldValidationErrorMessage(FIELD_T aFieldId, const wxString &aValue)
Return the error message if aValue is invalid for aFieldId.
Custom text control validator definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683