KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_properties_panel.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) 2020 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
23
25#include <font/fontconfig.h>
26#include <pgm_base.h>
27#include <common.h>
28#include <confirm.h>
29#include <connection_graph.h>
33#include <properties/property.h>
34#include <sch_commit.h>
35#include <sch_edit_frame.h>
36#include <sch_sheet.h>
37#include <symbol_edit_frame.h>
38#include <symbol_viewer_frame.h>
39#include <schematic.h>
40#include <sch_symbol.h>
41#include <lib_symbol.h>
42#include <sch_line.h>
43#include <sch_junction.h>
44#include <sch_field.h>
45#include <pin_map.h>
46#include <template_fieldnames.h>
48#include <string_utils.h>
49#include <tool/tool_manager.h>
50#include <tools/sch_actions.h>
53#include <wx_filename.h>
54
55
58
60 PROPERTIES_PANEL( aParent, aFrame ),
61 m_frame( aFrame ),
62 m_propMgr( PROPERTY_MANAGER::Instance() ),
63 m_unitEditorInstance( nullptr ),
64 m_checkboxEditorInstance( nullptr ),
65 m_colorEditorInstance( nullptr ),
66 m_fpEditorInstance( nullptr ),
67 m_urlEditorInstance( nullptr )
68{
69 addCategoryButton( _HKI( "Fields" ), _( "Add Field" ), BITMAPS::small_plus,
70 [this]()
71 {
73 } );
74
75 addCategoryButton( _HKI( "Custom Properties" ), _( "Add Custom Property" ), BITMAPS::small_plus,
76 [this]()
77 {
79 } );
80
82 _HKI( "Pin Map" ), _( "Edit Pin Map..." ), BITMAPS::small_edit,
83 [this]()
84 {
86 },
87 [this]()
88 {
89 return m_frame->IsType( FRAME_SCH ) && getSinglePinMappedSymbol() != nullptr;
90 },
91 /* aForceCategory */ true );
92
93 m_propMgr.Rebuild();
94 bool found = false;
95
96 wxASSERT( wxPGGlobalVars );
97
98 wxString editorKey = PG_UNIT_EDITOR::BuildEditorName( m_frame );
99
100 auto it = wxPGGlobalVars->m_mapEditorClasses.find( editorKey );
101
102 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
103 {
104 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( it->second );
105 m_unitEditorInstance->UpdateFrame( m_frame );
106 found = true;
107 }
108
109 if( !found )
110 {
111 PG_UNIT_EDITOR* new_editor = new PG_UNIT_EDITOR( m_frame );
112 m_unitEditorInstance = static_cast<PG_UNIT_EDITOR*>( wxPropertyGrid::RegisterEditorClass( new_editor ) );
113 }
114
115 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_CHECKBOX_EDITOR::EDITOR_NAME );
116
117 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
118 {
119 PG_CHECKBOX_EDITOR* cbEditor = new PG_CHECKBOX_EDITOR();
120 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( wxPropertyGrid::RegisterEditorClass( cbEditor ) );
121 }
122 else
123 {
124 m_checkboxEditorInstance = static_cast<PG_CHECKBOX_EDITOR*>( it->second );
125 }
126
127 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_COLOR_EDITOR::EDITOR_NAME );
128
129 if( it == wxPGGlobalVars->m_mapEditorClasses.end() )
130 {
131 PG_COLOR_EDITOR* colorEditor = new PG_COLOR_EDITOR();
132 m_colorEditorInstance = static_cast<PG_COLOR_EDITOR*>( wxPropertyGrid::RegisterEditorClass( colorEditor ) );
133 }
134 else
135 {
136 m_colorEditorInstance = static_cast<PG_COLOR_EDITOR*>( it->second );
137 }
138
139 auto netlistCallback = [this]()
140 {
141 SCH_SELECTION& sel = m_frame->GetToolManager()->GetTool<SCH_SELECTION_TOOL>()->GetSelection();
142 LIB_SYMBOL* libSymbol = nullptr;
143
144 for( EDA_ITEM* item : sel )
145 {
146 if( item->Type() == SCH_SYMBOL_T )
147 {
148 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
149
150 if( !libSymbol )
151 libSymbol = symbol->GetLibSymbolRef().get();
152 else if( libSymbol != symbol->GetLibSymbolRef().get() )
153 return std::string( "" );
154 }
155 }
156
157 if( !libSymbol )
158 return std::string( "" );
159
160 wxString symbolNetlist;
161 wxArrayString pins;
162
163 for( SCH_PIN* pin : libSymbol->GetGraphicalPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
164 pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
165
166 if( !pins.IsEmpty() )
167 symbolNetlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
168
169 symbolNetlist << wxS( "\r" );
170
171 wxArrayString fpFilters = libSymbol->GetFPFilters();
172
173 if( !fpFilters.IsEmpty() )
174 symbolNetlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
175
176 symbolNetlist << wxS( "\r" );
177
178 return symbolNetlist.ToStdString();
179 };
180
181 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
182
183 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
184 {
185 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( it->second );
186 m_fpEditorInstance->UpdateFrame( m_frame );
187 m_fpEditorInstance->UpdateCallback( netlistCallback );
188 }
189 else
190 {
191 PG_FPID_EDITOR* fpEditor = new PG_FPID_EDITOR( m_frame, netlistCallback );
192 m_fpEditorInstance = static_cast<PG_FPID_EDITOR*>( wxPropertyGrid::RegisterEditorClass( fpEditor ) );
193 }
194
195 it = wxPGGlobalVars->m_mapEditorClasses.find( PG_URL_EDITOR::BuildEditorName( m_frame ) );
196
197 if( it != wxPGGlobalVars->m_mapEditorClasses.end() )
198 {
199 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( it->second );
200 m_urlEditorInstance->UpdateFrame( m_frame );
201 }
202 else
203 {
204 PG_URL_EDITOR* urlEditor = new PG_URL_EDITOR( m_frame );
205 m_urlEditorInstance = static_cast<PG_URL_EDITOR*>( wxPropertyGrid::RegisterEditorClass( urlEditor ) );
206 }
207
208 Bind( wxEVT_MENU, &SCH_PROPERTIES_PANEL::onContextMenu, this, ID_CTX_ADD_FIELD );
212}
213
214
216{
217 m_unitEditorInstance->UpdateFrame( nullptr );
218 m_fpEditorInstance->UpdateFrame( nullptr );
219 m_urlEditorInstance->UpdateFrame( nullptr );
220}
221
222
224{
225 SCH_SELECTION_TOOL* selectionTool = m_frame->GetToolManager()->GetTool<SCH_SELECTION_TOOL>();
226 const SELECTION& selection = selectionTool->GetSelection();
227
228 if( selection.Empty() && m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR ) )
229 {
230 SYMBOL_EDIT_FRAME* symbolFrame = static_cast<SYMBOL_EDIT_FRAME*>( m_frame );
231
232 if( symbolFrame->GetCurSymbol() )
233 {
234 aFallbackSelection.Clear();
235 aFallbackSelection.Add( symbolFrame->GetCurSymbol() );
236 return aFallbackSelection;
237 }
238 }
239
240 return selection;
241}
242
243
245{
246 SELECTION fallbackSelection;
247 const SELECTION& selection = getSelection( fallbackSelection );
248
249 return selection.Empty() ? nullptr : selection.Front();
250}
251
252
254{
255 SELECTION fallbackSelection;
256 const SELECTION& selection = getSelection( fallbackSelection );
257
258 // Will actually just be updatePropertyValues() if selection hasn't changed
259 rebuildProperties( selection );
260}
261
262
264{
265 SELECTION fallbackSelection;
266 const SELECTION& selection = getSelection( fallbackSelection );
267
268 rebuildProperties( selection );
269}
270
271
273{
276
277 for( EDA_ITEM* item : aSelection )
278 {
279 if( item->Type() == SCH_JUNCTION_T )
280 {
282
283 // Dummy property which allows concurrently-selected wires to be edited
284 m_propMgr.AddProperty( new DUMMY_PROPERTY<SCH_JUNCTION, WIRE_STYLE>( _HKI( "Wire Style" ) ) )
285 .SetAvailableFunc(
286 []( INSPECTABLE* )
287 {
289 } );
290
291 // Dummy property which allows concurrently-selected wires to be edited
292 m_propMgr.AddProperty( new DUMMY_PROPERTY<SCH_JUNCTION, int>( _HKI( "Line Width" ) ) )
293 .SetAvailableFunc(
294 []( INSPECTABLE* )
295 {
297 } );
298 }
299 else if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T, SCH_ITEM_LOCATE_BUS_T } ) )
300 {
302
303 // Dummy property which allows concurrently-selected junctions to be edited
304 m_propMgr.AddProperty( new DUMMY_PROPERTY<SCH_LINE, int>( _HKI( "Diameter" ) ) )
305 .SetAvailableFunc(
306 []( INSPECTABLE* )
307 {
309 } );
310 }
311 }
312
314}
315
316
318{
319 SELECTION fallbackSelection;
320 const SELECTION& selection = getSelection( fallbackSelection );
321
322 if( selection.Size() != 1 || selection.Front()->Type() != SCH_SYMBOL_T )
323 return nullptr;
324
325 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( selection.Front() );
326
327 return symbol->HasEffectiveAssociatedFootprint() ? symbol : nullptr;
328}
329
330
332{
334
335 if( !symbol || !m_frame->IsType( FRAME_SCH ) )
336 return;
337
338 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_frame );
339
340 DIALOG_SYMBOL_PROPERTIES dlg( editFrame, symbol );
341 dlg.SelectPinMapPage();
342
343 // The dialog can subsequently invoke a KIWAY_PLAYER as a quasimodal frame, so it must run
344 // quasimodally to keep that support working.
345 int retval = dlg.ShowQuasiModal();
346
347 if( retval == SYMBOL_PROPS_EDIT_OK )
348 {
349 editFrame->OnModify();
350 AfterCommit();
351 }
352 else if( retval == SYMBOL_PROPS_WANT_SET_VARIANT_SYMBOL )
353 {
355 }
356 else if( retval == SYMBOL_PROPS_WANT_CLEAR_VARIANT_SYMBOL )
357 {
359 }
360}
361
362
363wxPGProperty* SCH_PROPERTIES_PANEL::createPGProperty( const PROPERTY_BASE* aProperty ) const
364{
365 wxPGProperty* prop = PGPropertyFactory( aProperty, m_frame );
366
367 if( auto colorProp = dynamic_cast<PGPROPERTY_COLOR4D*>( prop ) )
368 {
369 COLOR4D bg = m_frame->GetColorSettings()->GetColor( LAYER_SCHEMATIC_BACKGROUND );
370 colorProp->SetBackgroundColor( bg );
371 }
372
374 prop->SetEditor( PG_FPID_EDITOR::BuildEditorName( m_frame ) );
375 else if( aProperty->Name() == GetDefaultFieldName( FIELD_T::DATASHEET, UNTRANSLATED ) )
376 prop->SetEditor( PG_URL_EDITOR::BuildEditorName( m_frame ) );
377
378 return prop;
379}
380
381
382PROPERTY_BASE* SCH_PROPERTIES_PANEL::getPropertyFromEvent( const wxPropertyGridEvent& aEvent ) const
383{
384 EDA_ITEM* item = const_cast<SCH_PROPERTIES_PANEL*>( this )->getFrontItem();
385
386 if( !item || !item->IsSCH_ITEM() )
387 return nullptr;
388
389 SCH_ITEM* firstItem = static_cast<SCH_ITEM*>( item );
390
391 wxCHECK_MSG( firstItem, nullptr, wxT( "getPropertyFromEvent for a property with nothing selected!") );
392
393 PROPERTY_BASE* property = m_propMgr.GetProperty( firstItem, aEvent.GetPropertyName() );
394 wxCHECK_MSG( property, nullptr, wxT( "getPropertyFromEvent for a property not found on the selected item!" ) );
395
396 return property;
397}
398
399
400void SCH_PROPERTIES_PANEL::valueChanging( wxPropertyGridEvent& aEvent )
401{
403 return;
404
405 EDA_ITEM* frontItem = getFrontItem();
406
407 if( !frontItem )
408 return;
409
410 if( PROPERTY_BASE* property = getPropertyFromEvent( aEvent ) )
411 {
412 wxVariant newValue = aEvent.GetPropertyValue();
413
414 if( VALIDATOR_RESULT validationFailure = property->Validate( newValue.GetAny(), frontItem ) )
415 {
416 wxString errorMsg = wxString::Format( wxS( "%s: %s" ), wxGetTranslation( property->Name() ),
417 validationFailure->get()->Format( m_frame ) );
418 m_frame->ShowInfoBarError( errorMsg );
419 aEvent.Veto();
420 m_ValueChangeVetoed = true;
421 return;
422 }
423
424 aEvent.Skip();
425 }
426}
427
428
429void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
430{
432 return;
433
434 SELECTION fallbackSelection;
435 const SELECTION& selection = getSelection( fallbackSelection );
436
437 wxCHECK( getPropertyFromEvent( aEvent ), /* void */ );
438
439 wxVariant newValue = aEvent.GetPropertyValue();
440 SCH_COMMIT changes( m_frame );
441 SCH_SCREEN* screen = m_frame->GetScreen();
442
443 PROPERTY_COMMIT_HANDLER handler( &changes );
444
445 for( EDA_ITEM* edaItem : selection )
446 {
447 if( !edaItem->IsSCH_ITEM() )
448 continue;
449
450 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
451 PROPERTY_BASE* property = m_propMgr.GetProperty( item, aEvent.GetPropertyName() );
452 wxCHECK2( property, continue );
453
454 // Editing reference text in the schematic must go through the parent symbol in order to handle
455 // symbol instance data properly.
456 if( item->Type() == SCH_FIELD_T && static_cast<SCH_FIELD*>( item )->GetId() == FIELD_T::REFERENCE
457 && m_frame->IsType( FRAME_SCH )
458 && property->Name() == wxT( "Text" ) )
459 {
460 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParentSymbol() );
461 wxCHECK2( symbol, continue );
462
463 changes.Modify( symbol, screen, RECURSE_MODE::NO_RECURSE );
464 symbol->SetRefProp( newValue.GetString() );
465 symbol->SyncOtherUnits( symbol->Schematic()->CurrentSheet(), changes, property );
466 continue;
467 }
468
469 // Editing field text in the schematic when a variant is active must use variant-aware
470 // SetText to properly store the value as a variant override.
471 if( item->Type() == SCH_FIELD_T
472 && m_frame->IsType( FRAME_SCH )
473 && property->Name() == wxT( "Text" ) )
474 {
475 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
476 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item->GetParentSymbol() );
477
478 if( symbol && symbol->Schematic() )
479 {
480 wxString variantName = symbol->Schematic()->GetCurrentVariant();
481
482 if( !variantName.IsEmpty() )
483 {
484 changes.Modify( symbol, screen, RECURSE_MODE::NO_RECURSE );
485 field->SetText( newValue.GetString(), &symbol->Schematic()->CurrentSheet(), variantName );
486 symbol->SyncOtherUnits( symbol->Schematic()->CurrentSheet(), changes, nullptr, variantName );
487 continue;
488 }
489 }
490 }
491
492 // Changing a sheet's filename field requires file operations to match the dialog behavior.
493 if( item->Type() == SCH_FIELD_T
494 && m_frame->IsType( FRAME_SCH )
495 && property->Name() == wxT( "Text" ) )
496 {
497 SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
498 SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item->GetParent() );
499
500 if( sheet && field->GetId() == FIELD_T::SHEET_FILENAME )
501 {
502 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_frame );
503
504 if( !handleSheetFilenameChange( editFrame, sheet, changes, newValue.GetString() ) )
505 {
506 UpdateData();
507 return;
508 }
509
510 continue;
511 }
512 }
513
514 if( item->Type() == SCH_TABLECELL_T )
515 changes.Modify( item->GetParent(), screen, RECURSE_MODE::NO_RECURSE );
516 else
517 changes.Modify( item, screen, RECURSE_MODE::NO_RECURSE );
518
519 item->Set( property, newValue );
520
521 if( SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( item ) )
522 {
523 symbol->SyncOtherUnits( symbol->Schematic()->CurrentSheet(), changes, property,
524 symbol->Schematic()->GetCurrentVariant() );
525 }
526 }
527
528 changes.Push( _( "Edit Properties" ) );
529
530 // Force a repaint of the items whose properties were changed
531 // This is necessary to update field displays in the schematic view
532 for( EDA_ITEM* edaItem : selection )
533 m_frame->UpdateItem( edaItem );
534
535 // Perform grid updates as necessary based on value change
536 AfterCommit();
537
538 aEvent.Skip();
539}
540
541
543 SCH_COMMIT& aChanges,
544 const wxString& aNewFilename )
545{
546 wxString newFilename = EnsureFileExtension( aNewFilename, FILEEXT::KiCadSchematicFileExtension );
547
548 if( newFilename.IsEmpty() || !IsFullFileNameValid( newFilename ) )
549 {
550 DisplayError( aFrame, _( "A sheet must have a valid file name." ) );
551 return false;
552 }
553
554 // Normalize separators to unix notation
555 newFilename.Replace( wxT( "\\" ), wxT( "/" ) );
556
557 wxString oldFilename = aSheet->GetFileName();
558 oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
559
560 if( newFilename == oldFilename )
561 return true;
562
563 if( !aFrame->ChangeSheetFile( aSheet, newFilename ) )
564 return false;
565
566 SCH_SCREEN* currentScreen = aFrame->GetCurrentSheet().LastScreen();
567 aChanges.Modify( aSheet, currentScreen, RECURSE_MODE::NO_RECURSE );
568 aSheet->SetFileName( newFilename );
569
570 return true;
571}
572
573
574bool SCH_PROPERTIES_PANEL::isKeyEditable( const wxPGProperty* aPGProp ) const
575{
576 PROPERTY_BASE* prop = static_cast<PROPERTY_BASE*>( aPGProp->GetClientData() );
577
578 if( !prop )
579 return false;
580
581 EDA_ITEM* item = const_cast<SCH_PROPERTIES_PANEL*>( this )->getFrontItem();
582
583 if( !item )
584 return false;
585
586 if( prop->Group() == _HKI( "Custom Properties" ) )
587 return true;
588
589 if( item->Type() == SCH_SYMBOL_T )
590 {
591 SCH_FIELD* field = static_cast<SCH_SYMBOL*>( item )->GetField( prop->Name() );
592 return field && !field->IsMandatory();
593 }
594 else if( item->Type() == SCH_SHEET_T )
595 {
596 SCH_FIELD* field = static_cast<SCH_SHEET*>( item )->GetField( prop->Name() );
597 return field && !field->IsMandatory();
598 }
599
600 return false;
601}
602
603
604bool SCH_PROPERTIES_PANEL::isKeyNameInUse( const wxString& aName ) const
605{
606 EDA_ITEM* item = const_cast<SCH_PROPERTIES_PANEL*>( this )->getFrontItem();
607
608 if( !item )
609 return false;
610
611 return m_propMgr.GetProperty( item, aName ) != nullptr;
612}
613
614
615void SCH_PROPERTIES_PANEL::onKeyRenamed( const wxString& aOldName, const wxString& aNewName )
616{
617 SELECTION fallbackSelection;
618 const SELECTION& selection = getSelection( fallbackSelection );
619
620 SCH_COMMIT changes( m_frame );
621 SCH_SCREEN* screen = m_frame->GetScreen();
622 PROPERTY_COMMIT_HANDLER handler( &changes );
623
624 for( EDA_ITEM* edaItem : selection )
625 {
626 if( !edaItem->IsSCH_ITEM() )
627 continue;
628
629 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
630 bool renamed = false;
631
632 if( item->Type() == SCH_SYMBOL_T )
633 {
634 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
635 SCH_FIELD* field = symbol->GetField( aOldName );
636
637 if( field && !field->IsMandatory() )
638 {
639 changes.Modify( symbol, screen, RECURSE_MODE::NO_RECURSE );
640 field->SetName( aNewName );
641 renamed = true;
642 }
643 }
644 else if( item->Type() == SCH_SHEET_T )
645 {
646 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
647 SCH_FIELD* field = sheet->GetField( aOldName );
648
649 if( field && !field->IsMandatory() )
650 {
651 changes.Modify( sheet, screen, RECURSE_MODE::NO_RECURSE );
652 field->SetName( aNewName );
653 renamed = true;
654 }
655 }
656
657 if( !renamed )
658 {
659 if( wxString value; item->GetCustomProperty( aOldName, value ) )
660 {
661 changes.Modify( item, screen, RECURSE_MODE::NO_RECURSE );
662 item->RemoveCustomProperty( aOldName );
663 item->SetCustomProperty( aNewName, value );
664 }
665 }
666 }
667
668 changes.Push( _( "Rename Property" ) );
669
670 AfterCommit();
671}
672
673
674bool SCH_PROPERTIES_PANEL::buildContextMenu( wxMenu& aMenu, wxPGProperty* aPGProp )
675{
676 if( aPGProp->IsCategory() )
677 {
678 if( aPGProp->GetLabel() == wxGetTranslation( _HKI( "Fields" ) ) )
679 aMenu.Append( ID_CTX_ADD_FIELD, _( "Add Field" ) );
680 else if( aPGProp->GetLabel() == wxGetTranslation( _HKI( "Custom Properties" ) ) )
681 aMenu.Append( ID_CTX_ADD_CUSTOM_PROPERTY, _( "Add Custom Property" ) );
682 }
683 else
684 {
685 PROPERTY_BASE* prop = static_cast<PROPERTY_BASE*>( aPGProp->GetClientData() );
686
687 if( !prop )
688 return false;
689
690 if( prop->Group() == _HKI( "Fields" ) )
691 {
692 if( isKeyEditable( aPGProp ) )
693 aMenu.Append( ID_CTX_REMOVE_FIELD, _( "Remove Field" ) );
694
695 aMenu.Append( ID_CTX_ADD_FIELD, _( "Add Field" ) );
696 }
697 else if( prop->Group() == _HKI( "Custom Properties" ) )
698 {
699 aMenu.Append( ID_CTX_REMOVE_CUSTOM_PROPERTY, _( "Remove Custom Property" ) );
700 aMenu.Append( ID_CTX_ADD_CUSTOM_PROPERTY, _( "Add Custom Property" ) );
701 }
702 }
703
704 return aMenu.GetMenuItemCount() > 0;
705}
706
707
708void SCH_PROPERTIES_PANEL::onContextMenu( wxCommandEvent& aEvent )
709{
710 switch( aEvent.GetId() )
711 {
712 case ID_CTX_ADD_FIELD: addBlankField(); break;
716 default: break;
717 }
718}
719
720
722{
723 SELECTION fallbackSelection;
724 const SELECTION& selection = getSelection( fallbackSelection );
725
727
728 if( selection.Empty() )
729 return;
730
731 wxString name;
732
733 for( int n = 0; ; ++n )
734 {
736 bool used = false;
737
738 for( EDA_ITEM* item : selection )
739 {
740 if( item->Type() == SCH_SYMBOL_T && static_cast<SCH_SYMBOL*>( item )->GetField( name ) )
741 used = true;
742 else if( item->Type() == SCH_SHEET_T && static_cast<SCH_SHEET*>( item )->GetField( name ) )
743 used = true;
744 }
745
746 if( !used )
747 break;
748 }
749
750 SCH_COMMIT changes( m_frame );
751 SCH_SCREEN* screen = m_frame->GetScreen();
752 PROPERTY_COMMIT_HANDLER handler( &changes );
753
754 for( EDA_ITEM* edaItem : selection )
755 {
756 if( !edaItem->IsSCH_ITEM() )
757 continue;
758
759 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
760
761 if( item->Type() == SCH_SYMBOL_T )
762 {
763 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
764
765 changes.Modify( symbol, screen, RECURSE_MODE::NO_RECURSE );
766 symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, name ) )->SetVisible( false );
767 }
768 else if( item->Type() == SCH_SHEET_T )
769 {
770 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
771
772 changes.Modify( sheet, screen, RECURSE_MODE::NO_RECURSE );
773 sheet->AddField( SCH_FIELD( sheet, FIELD_T::SHEET_USER, name ) )->SetVisible( false );
774 }
775 }
776
777 changes.Push( _( "Add Field" ) );
778 AfterCommit();
779
781
782 beginLabelEdit( name, true );
783}
784
785
787{
788 SELECTION fallbackSelection;
789 const SELECTION& selection = getSelection( fallbackSelection );
790
792
793 if( selection.Empty() )
794 return;
795
796 wxString name;
797
798 for( int n = 0; ; ++n )
799 {
800 name = wxString::Format( wxS( "Property%d" ), n );
801 bool used = false;
802
803 for( EDA_ITEM* item : selection )
804 {
805 if( wxString dummy; item->GetCustomProperty( name, dummy ) )
806 {
807 used = true;
808 break;
809 }
810 }
811
812 if( !used )
813 break;
814 }
815
816 SCH_COMMIT changes( m_frame );
817 SCH_SCREEN* screen = m_frame->GetScreen();
818 PROPERTY_COMMIT_HANDLER handler( &changes );
819
820 for( EDA_ITEM* edaItem : selection )
821 {
822 if( !edaItem->IsSCH_ITEM() )
823 continue;
824
825 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
826
827 changes.Modify( item, screen, RECURSE_MODE::NO_RECURSE );
828 item->SetCustomProperty( name, wxEmptyString );
829 }
830
831 changes.Push( _( "Add Custom Property" ) );
832 AfterCommit();
833
835
836 beginLabelEdit( name, true );
837}
838
839
840void SCH_PROPERTIES_PANEL::removeField( const wxString& aName )
841{
842 SELECTION fallbackSelection;
843 const SELECTION& selection = getSelection( fallbackSelection );
844
845 SCH_COMMIT changes( m_frame );
846 SCH_SCREEN* screen = m_frame->GetScreen();
847 PROPERTY_COMMIT_HANDLER handler( &changes );
848
849 for( EDA_ITEM* edaItem : selection )
850 {
851 if( !edaItem->IsSCH_ITEM() )
852 continue;
853
854 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
855
856 if( item->Type() == SCH_SYMBOL_T )
857 {
858 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
859 SCH_FIELD* field = symbol->GetField( aName );
860
861 if( field && !field->IsMandatory() )
862 {
863 changes.Modify( symbol, screen, RECURSE_MODE::NO_RECURSE );
864 symbol->RemoveField( aName );
865 }
866 }
867 else if( item->Type() == SCH_SHEET_T )
868 {
869 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
870 auto& fields = sheet->GetFields();
871
872 for( auto it = fields.begin(); it != fields.end(); ++it )
873 {
874 if( !it->IsMandatory() && it->GetName() == aName )
875 {
876 changes.Modify( sheet, screen, RECURSE_MODE::NO_RECURSE );
877 fields.erase( it );
878 break;
879 }
880 }
881 }
882 }
883
884 changes.Push( _( "Remove Field" ) );
885 AfterCommit();
886}
887
888
890{
891 SELECTION fallbackSelection;
892 const SELECTION& selection = getSelection( fallbackSelection );
893
894 SCH_COMMIT changes( m_frame );
895 SCH_SCREEN* screen = m_frame->GetScreen();
896 PROPERTY_COMMIT_HANDLER handler( &changes );
897
898 for( EDA_ITEM* edaItem : selection )
899 {
900 if( !edaItem->IsSCH_ITEM() )
901 continue;
902
903 SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
904
905 changes.Modify( item, screen, RECURSE_MODE::NO_RECURSE );
906 item->RemoveCustomProperty( aName );
907 }
908
909 changes.Push( _( "Remove Custom Property" ) );
910 AfterCommit();
911}
912
913
915{
916 // Note: currently assuming that any newly-created item from the panel is either a field or
917 // a custom property because those are the types we currently support.
918 if( EDA_ITEM* item = getFrontItem() )
919 {
920 if( item->Type() == SCH_SYMBOL_T && static_cast<SCH_SYMBOL*>( item )->GetField( aKey ) )
921 removeField( aKey );
922 else if( item->Type() == SCH_SHEET_T && static_cast<SCH_SHEET*>( item )->GetField( aKey ) )
923 removeField( aKey );
924 else
925 removeCustomProperty( aKey );
926 }
927}
928
929
930void SCH_PROPERTIES_PANEL::OnLanguageChanged( wxCommandEvent& aEvent )
931{
933
934 aEvent.Skip();
935}
936
937
938bool SCH_PROPERTIES_PANEL::getItemValue( EDA_ITEM* aItem, PROPERTY_BASE* aProperty, wxVariant& aValue )
939{
940 // For SCH_FIELD "Text" property, return the variant-aware value when a variant is active
941 if( aItem->Type() == SCH_FIELD_T
942 && m_frame->IsType( FRAME_SCH )
943 && aProperty->Name() == wxT( "Text" ) )
944 {
945 SCH_FIELD* field = static_cast<SCH_FIELD*>( aItem );
946 SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( field->GetParentSymbol() );
947
948 if( symbol && symbol->Schematic() )
949 {
950 wxString variantName = symbol->Schematic()->GetCurrentVariant();
951
952 if( !variantName.IsEmpty() )
953 {
954 wxString text = field->GetText( &symbol->Schematic()->CurrentSheet(), variantName );
955 aValue = wxVariant( text );
956 return true;
957 }
958 }
959 }
960
961 return PROPERTIES_PANEL::getItemValue( aItem, aProperty, aValue );
962}
const char * name
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
Dialog used to edit SCH_SYMBOL objects in a schematic.
void SelectPinMapPage()
Select the Pin Map page so the dialog opens directly on the pin-to-pad mapping editor (issue #2282).
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
bool GetCustomProperty(const wxString &aKey, wxString &aValue) const
Definition eda_item.cpp:188
void RemoveCustomProperty(const wxString &aKey)
Definition eda_item.cpp:161
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM * GetParent() const
Definition eda_item.h:112
void SetCustomProperty(const wxString &aKey, const wxString &aValue)
Definition eda_item.h:255
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
bool Set(PROPERTY_BASE *aProperty, wxAny &aValue, bool aNotify=true)
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
bool IsSCH_ITEM() const
Definition view_item.h:97
Define a library symbol object.
Definition lib_symbol.h:114
wxArrayString GetFPFilters() const
Definition lib_symbol.h:252
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const override
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
static const wxString EDITOR_NAME
Definition pg_editors.h:75
static const wxString EDITOR_NAME
Definition pg_editors.h:91
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
static wxString BuildEditorName(EDA_DRAW_FRAME *aFrame)
wxString m_contextMenuPropertyName
PROPERTIES_PANEL(wxWindow *aParent, EDA_BASE_FRAME *aFrame)
void beginLabelEdit(const wxString &aKey, bool aStartBlank=false)
void settlePendingLabelEdit()
Synchronously ends any in-progress label edit; potentially canceling a newly added row.
virtual void OnLanguageChanged(wxCommandEvent &aEvent)
virtual bool getItemValue(EDA_ITEM *aItem, PROPERTY_BASE *aProperty, wxVariant &aValue)
Utility to fetch a property value and convert to wxVariant Precondition: aItem is known to have prope...
virtual void rebuildProperties(const SELECTION &aSelection)
Generates the property grid for a given selection of items.
void addCategoryButton(const wxString &aGroupKey, const wxString &aTooltip, BITMAPS aBitmap, std::function< void()> aAction, std::function< bool()> aEnableFunc=nullptr, bool aForceCategory=false)
Registers an overlay button on a category caption row.
wxString m_pendingNewKey
Key of a freshly-added blank field/custom property awaiting a name from the user.
wxString Group() const
Definition property.h:377
const wxString & Name() const
Definition property.h:221
Provide class metadata.
wxString GetCurrentVariant() const
Return the current variant being edited.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:312
static TOOL_ACTION clearVariantSymbol
static TOOL_ACTION setVariantSymbol
A shim class between EDA_DRAW_FRAME and several derived classes: SYMBOL_EDIT_FRAME,...
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SHEET_PATH & GetCurrentSheet() const
bool ChangeSheetFile(SCH_SHEET *aSheet, const wxString &aNewFilename, bool *aClearAnnotationNewItems=nullptr, bool *aIsUndoable=nullptr, const wxString *aSourceSheetFilename=nullptr)
Change the file backing a schematic sheet.
Definition sheet.cpp:175
bool IsMandatory() const
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:139
FIELD_T GetId() const
Definition sch_field.h:143
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
const SYMBOL * GetParentSymbol() const
Definition sch_item.cpp:350
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:302
bool getItemValue(EDA_ITEM *aItem, PROPERTY_BASE *aProperty, wxVariant &aValue) override
Utility to fetch a property value and convert to wxVariant Precondition: aItem is known to have prope...
void onContextMenu(wxCommandEvent &aEvent)
bool buildContextMenu(wxMenu &aMenu, wxPGProperty *aPGProp) override
bool isKeyEditable(const wxPGProperty *aPGProp) const override
wxPGProperty * createPGProperty(const PROPERTY_BASE *aProperty) const override
PROPERTY_MANAGER & m_propMgr
void removeCustomProperty(const wxString &aName)
PG_CHECKBOX_EDITOR * m_checkboxEditorInstance
PG_FPID_EDITOR * m_fpEditorInstance
const SELECTION & getSelection(SELECTION &aFallbackSelection)
Get the current selection from the selection tool.
void onEditPinMap()
Open the symbol properties dialog on its Pin Map page for the single selected symbol (issue #2282).
void valueChanging(wxPropertyGridEvent &aEvent) override
PG_UNIT_EDITOR * m_unitEditorInstance
bool isKeyNameInUse(const wxString &aName) const override
void removeField(const wxString &aName)
void valueChanged(wxPropertyGridEvent &aEvent) override
void onKeyRenamed(const wxString &aOldName, const wxString &aNewName) override
SCH_PROPERTIES_PANEL(wxWindow *aParent, SCH_BASE_FRAME *aFrame)
void onNewItemLeftBlank(const wxString &aKey) override
PG_COLOR_EDITOR * m_colorEditorInstance
EDA_ITEM * getFrontItem()
Get the front item of the current selection.
PROPERTY_BASE * getPropertyFromEvent(const wxPropertyGridEvent &aEvent) const
void OnLanguageChanged(wxCommandEvent &aEvent) override
bool handleSheetFilenameChange(SCH_EDIT_FRAME *aFrame, SCH_SHEET *aSheet, SCH_COMMIT &aChanges, const wxString &aNewFilename)
void rebuildProperties(const SELECTION &aSelection) override
Generates the property grid for a given selection of items.
PG_URL_EDITOR * m_urlEditorInstance
SCH_SYMBOL * getSinglePinMappedSymbol()
SCH_SELECTION & GetSelection()
SCH_SCREEN * LastScreen()
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:398
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:392
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition sch_sheet.h:91
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add aFieldName to the list of fields.
Schematic symbol object.
Definition sch_symbol.h:75
void SetRefProp(const wxString &aRef)
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
void SyncOtherUnits(const SCH_SHEET_PATH &aSourceSheet, SCH_COMMIT &aCommit, PROPERTY_BASE *aProperty, const wxString &aVariantName=wxEmptyString)
Keep fields other than the reference, include/exclude flags, and alternate pin assignments in sync in...
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:184
bool HasEffectiveAssociatedFootprint() const
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
virtual void Add(EDA_ITEM *aItem)
A null aItem is ignored; the selection never holds null members.
Definition selection.cpp:38
EDA_ITEM * Front() const
Definition selection.h:176
virtual void Clear() override
Remove all the stored items from the group.
Definition selection.h:97
int Size() const
Returns the number of selected parts.
Definition selection.h:120
bool Empty() const
Checks if there is anything selected.
Definition selection.h:114
The symbol library editor main window.
LIB_SYMBOL * GetCurSymbol() const
Return the current symbol being edited or NULL if none selected.
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:880
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
@ SYMBOL_PROPS_WANT_SET_VARIANT_SYMBOL
@ SYMBOL_PROPS_EDIT_OK
@ SYMBOL_PROPS_WANT_CLEAR_VARIANT_SYMBOL
#define _(s)
@ NO_RECURSE
Definition eda_item.h:52
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ FRAME_SCH
Definition frame_type.h:30
static const std::string KiCadSchematicFileExtension
@ LAYER_SCHEMATIC_BACKGROUND
Definition layer_ids.h:516
#define _HKI(x)
Definition page_info.cpp:40
wxPGProperty * PGPropertyFactory(const PROPERTY_BASE *aProperty, EDA_DRAW_FRAME *aFrame)
see class PGM_BASE
APIIMPORT wxPGGlobalVarsClass * wxPGGlobalVars
@ ID_CTX_REMOVE_CUSTOM_PROPERTY
@ ID_CTX_REMOVE_FIELD
@ ID_CTX_ADD_CUSTOM_PROPERTY
@ ID_CTX_ADD_FIELD
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
std::vector< FAB_LAYER_COLOR > dummy
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
bool IsFullFileNameValid(const wxString &aFullFilename)
Checks if a full filename is valid, i.e.
@ CTX_LINE
wxString GetUserFieldName(int aFieldNdx, TRANSLATION aTranslation)
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.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ UNTRANSLATED
KIBIS_PIN * pin
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_TABLECELL_T
Definition typeinfo.h:162
@ SCH_FIELD_T
Definition typeinfo.h:146
@ SCH_SHEET_T
Definition typeinfo.h:171
@ SCH_JUNCTION_T
Definition typeinfo.h:155
Definition of file extensions used in Kicad.