KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema/cross-probing.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) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
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 2
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, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <kiface_base.h>
27#include <kiway.h>
28#include <kiway_express.h>
29#include <eda_dde.h>
30#include <connection_graph.h>
31#include <sch_sheet.h>
32#include <sch_symbol.h>
33#include <sch_reference_list.h>
34#include <string_utils.h>
38#include <project_sch.h>
39#include <richio.h>
40#include <tools/sch_actions.h>
42#include <advanced_config.h>
43
44#include <pgm_base.h>
47#include <wx/log.h>
48#include <trace_helpers.h>
49
50SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wxString* aReference,
51 bool aSearchHierarchy, SCH_SEARCH_T aSearchType,
52 const wxString& aSearchText )
53{
54 SCH_SHEET_PATH* sheetWithSymbolFound = nullptr;
55 SCH_SYMBOL* symbol = nullptr;
56 SCH_PIN* pin = nullptr;
57 SCH_SHEET_LIST sheetList;
58 SCH_ITEM* foundItem = nullptr;
59
60 if( !aSearchHierarchy )
61 sheetList.push_back( m_frame->GetCurrentSheet() );
62 else
63 sheetList = m_frame->Schematic().Hierarchy();
64
65 for( SCH_SHEET_PATH& sheet : sheetList )
66 {
67 SCH_SCREEN* screen = sheet.LastScreen();
68
69 for( EDA_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
70 {
71 SCH_SYMBOL* candidate = static_cast<SCH_SYMBOL*>( item );
72
73 // Search by path if specified, otherwise search by reference
74 bool found = false;
75
76 if( aPath )
77 {
78 wxString path = sheet.PathAsString() + candidate->m_Uuid.AsString();
79 found = ( *aPath == path );
80 }
81 else
82 {
83 found = ( aReference && aReference->CmpNoCase( candidate->GetRef( &sheet ) ) == 0 );
84 }
85
86 if( found )
87 {
88 symbol = candidate;
89 sheetWithSymbolFound = &sheet;
90
91 if( aSearchType == HIGHLIGHT_PIN )
92 {
93 pin = symbol->GetPin( aSearchText );
94
95 // Ensure we have found the right unit in case of multi-units symbol
96 if( pin )
97 {
98 int unit = pin->GetLibPin()->GetUnit();
99
100 if( unit != 0 && unit != symbol->GetUnit() )
101 {
102 pin = nullptr;
103 continue;
104 }
105
106 // Get pin position in true schematic coordinate
107 foundItem = pin;
108 break;
109 }
110 }
111 else
112 {
113 foundItem = symbol;
114 break;
115 }
116 }
117 }
118
119 if( foundItem )
120 break;
121 }
122
123 CROSS_PROBING_SETTINGS& crossProbingSettings = m_frame->eeconfig()->m_CrossProbing;
124
125 if( symbol )
126 {
127 if( *sheetWithSymbolFound != m_frame->GetCurrentSheet() )
128 {
129 m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( SCH_ACTIONS::changeSheet,
130 sheetWithSymbolFound );
131 }
132
133 if( crossProbingSettings.center_on_items )
134 {
135 if( crossProbingSettings.zoom_to_fit )
136 {
137 BOX2I bbox = symbol->GetBoundingBox();
138
139 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->ZoomFitCrossProbeBBox( bbox );
140 }
141
142 if( pin )
143 m_frame->FocusOnItem( pin );
144 else
145 m_frame->FocusOnItem( symbol );
146 }
147 }
148
149 /* Print diag */
150 wxString msg;
151 wxString displayRef;
152
153 if( aReference )
154 displayRef = *aReference;
155 else if( aPath )
156 displayRef = *aPath;
157
158 if( symbol )
159 {
160 if( aSearchType == HIGHLIGHT_PIN )
161 {
162 if( foundItem )
163 msg.Printf( _( "%s pin %s found" ), displayRef, aSearchText );
164 else
165 msg.Printf( _( "%s found but pin %s not found" ), displayRef, aSearchText );
166 }
167 else
168 {
169 msg.Printf( _( "%s found" ), displayRef );
170 }
171 }
172 else
173 {
174 msg.Printf( _( "%s not found" ), displayRef );
175 }
176
177 m_frame->SetStatusText( msg );
178 m_frame->GetCanvas()->Refresh();
179
180 return foundItem;
181}
182
183
184/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
185 *
186 * Commands are:
187 *
188 * $PART: "reference" Put cursor on symbol.
189 * $PART: "reference" $REF: "ref" Put cursor on symbol reference.
190 * $PART: "reference" $VAL: "value" Put cursor on symbol value.
191 * $PART: "reference" $PAD: "pin name" Put cursor on the symbol pin.
192 * $NET: "netname" Highlight a specified net
193 * $CLEAR: "HIGHLIGHTED" Clear symbols highlight
194 *
195 * $CONFIG Show the Manage Symbol Libraries dialog
196 * $ERC Show the ERC dialog
197 */
198void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
199{
201 char line[1024];
202
203 strncpy( line, cmdline, sizeof( line ) - 1 );
204 line[ sizeof( line ) - 1 ] = '\0';
205
206 char* idcmd = strtok( line, " \n\r" );
207 char* text = strtok( nullptr, "\"\n\r" );
208
209 if( idcmd == nullptr )
210 return;
211
212 CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing;
213
214 if( strcmp( idcmd, "$CONFIG" ) == 0 )
215 {
217 return;
218 }
219 else if( strcmp( idcmd, "$ERC" ) == 0 )
220 {
222 return;
223 }
224 else if( strcmp( idcmd, "$NET:" ) == 0 )
225 {
226 if( !crossProbingSettings.auto_highlight )
227 return;
228
229 wxString netName = From_UTF8( text );
230
231 if( auto sg = Schematic().ConnectionGraph()->FindFirstSubgraphByName( netName ) )
232 m_highlightedConn = sg->GetDriverConnection()->Name();
233 else
234 m_highlightedConn = wxEmptyString;
235
238
239 SetStatusText( _( "Highlighted net:" ) + wxS( " " ) + UnescapeString( netName ) );
240 return;
241 }
242 else if( strcmp( idcmd, "$CLEAR:" ) == 0 )
243 {
244 // Cross-probing is now done through selection so we no longer need a clear command
245 return;
246 }
247
248 if( !crossProbingSettings.on_selection )
249 return;
250
251 if( text == nullptr )
252 return;
253
254 if( strcmp( idcmd, "$PART:" ) != 0 )
255 return;
256
257 wxString part_ref = From_UTF8( text );
258
259 /* look for a complement */
260 idcmd = strtok( nullptr, " \n\r" );
261
262 if( idcmd == nullptr ) // Highlight symbol only (from CvPcb or Pcbnew)
263 {
264 // Highlight symbol part_ref, or clear Highlight, if part_ref is not existing
265 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
266 return;
267 }
268
269 text = strtok( nullptr, "\"\n\r" );
270
271 if( text == nullptr )
272 return;
273
274 wxString msg = From_UTF8( text );
275
276 if( strcmp( idcmd, "$REF:" ) == 0 )
277 {
278 // Highlighting the reference itself isn't actually that useful, and it's harder to
279 // see. Highlight the parent and display the message.
280 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
281 }
282 else if( strcmp( idcmd, "$VAL:" ) == 0 )
283 {
284 // Highlighting the value itself isn't actually that useful, and it's harder to see.
285 // Highlight the parent and display the message.
286 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
287 }
288 else if( strcmp( idcmd, "$PAD:" ) == 0 )
289 {
290 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_PIN, msg );
291 }
292 else
293 {
294 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
295 }
296}
297
298
299void SCH_EDIT_FRAME::SendSelectItemsToPcb( const std::vector<EDA_ITEM*>& aItems, bool aForce )
300{
301 std::vector<wxString> parts;
302
303 for( EDA_ITEM* item : aItems )
304 {
305 switch( item->Type() )
306 {
307 case SCH_SYMBOL_T:
308 {
309 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
310 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
311
312 parts.push_back( wxT( "F" ) + EscapeString( ref, CTX_IPC ) );
313 break;
314 }
315
316 case SCH_SHEET_T:
317 {
318 // For cross probing, we need the full path of the sheet, because
319 // we search by the footprint path prefix in the PCB editor
320 wxString full_path = GetCurrentSheet().PathAsString() + item->m_Uuid.AsString();
321
322 parts.push_back( wxT( "S" ) + full_path );
323 break;
324 }
325
326 case SCH_PIN_T:
327 {
328 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
329 SYMBOL* symbol = pin->GetParentSymbol();
330 wxString ref = symbol->GetRef( &GetCurrentSheet(), false );
331
332 parts.push_back( wxT( "P" ) + EscapeString( ref, CTX_IPC ) + wxT( "/" )
333 + EscapeString( pin->GetShownNumber(), CTX_IPC ) );
334 break;
335 }
336
337 default:
338 break;
339 }
340 }
341
342 if( parts.empty() )
343 return;
344
345 std::string command = "$SELECT: 0,";
346
347 for( wxString part : parts )
348 {
349 command += part;
350 command += ",";
351 }
352
353 command.pop_back();
354
355 if( Kiface().IsSingle() )
356 {
357 SendCommand( MSG_TO_PCB, command );
358 }
359 else
360 {
361 // Typically ExpressMail is going to be s-expression packets, but since
362 // we have existing interpreter of the selection packet on the other
363 // side in place, we use that here.
365 command, this );
366 }
367}
368
369
370void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
371{
372 // The command is a keyword followed by a quoted string.
373
374 std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
375
376 if( !packet.empty() )
377 {
378 if( Kiface().IsSingle() )
379 {
380 SendCommand( MSG_TO_PCB, packet );
381 }
382 else
383 {
384 // Typically ExpressMail is going to be s-expression packets, but since
385 // we have existing interpreter of the cross probe packet on the other
386 // side in place, we use that here.
388 }
389 }
390}
391
392
394{
395 if( !aConnection )
396 {
398 return;
399 }
400
401 if( aConnection->IsNet() )
402 {
403 SendCrossProbeNetName( aConnection->Name() );
404 return;
405 }
406
407 if( aConnection->Members().empty() )
408 return;
409
410 auto all_members = aConnection->AllMembers();
411
412 wxString nets = all_members[0]->Name();
413
414 if( all_members.size() == 1 )
415 {
416 SendCrossProbeNetName( nets );
417 return;
418 }
419
420 // TODO: This could be replaced by just sending the bus name once we have bus contents
421 // included as part of the netlist sent from Eeschema to Pcbnew (and thus Pcbnew can
422 // natively keep track of bus membership)
423
424 for( size_t i = 1; i < all_members.size(); i++ )
425 nets << "," << all_members[i]->Name();
426
427 std::string packet = StrPrintf( "$NETS: \"%s\"", TO_UTF8( nets ) );
428
429 if( !packet.empty() )
430 {
431 if( Kiface().IsSingle() )
432 SendCommand( MSG_TO_PCB, packet );
433 else
434 {
435 // Typically ExpressMail is going to be s-expression packets, but since
436 // we have existing interpreter of the cross probe packet on the other
437 // side in place, we use that here.
439 }
440 }
441}
442
443
445{
446 std::string packet = "$CLEAR\n";
447
448 if( Kiface().IsSingle() )
449 {
450 SendCommand( MSG_TO_PCB, packet );
451 }
452 else
453 {
454 // Typically ExpressMail is going to be s-expression packets, but since
455 // we have existing interpreter of the cross probe packet on the other
456 // side in place, we use that here.
458 }
459}
460
461
463 const SCH_SHEET_LIST& aSchematicSheetList, const SCH_SHEET_PATH& aSheetPath,
464 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
465 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
466 bool aRecursive = false )
467{
468 if( aRecursive )
469 {
470 // Iterate over children
471 for( const SCH_SHEET_PATH& candidate : aSchematicSheetList )
472 {
473 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
474 continue;
475
476 findSymbolsAndPins( aSchematicSheetList, candidate, aSyncSymMap, aSyncPinMap,
477 aRecursive );
478 }
479 }
480
481 SCH_REFERENCE_LIST references;
482
483 aSheetPath.GetSymbols( references, false, true );
484
485 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
486 {
487 SCH_REFERENCE& schRef = references[ii];
488
489 if( schRef.IsSplitNeeded() )
490 schRef.Split();
491
492 SCH_SYMBOL* symbol = schRef.GetSymbol();
493 wxString refNum = schRef.GetRefNumber();
494 wxString fullRef = schRef.GetRef() + refNum;
495
496 // Skip power symbols
497 if( fullRef.StartsWith( wxS( "#" ) ) )
498 continue;
499
500 // Unannotated symbols are not supported
501 if( refNum.compare( wxS( "?" ) ) == 0 )
502 continue;
503
504 // Look for whole footprint
505 auto symMatchIt = aSyncSymMap.find( fullRef );
506
507 if( symMatchIt != aSyncSymMap.end() )
508 {
509 symMatchIt->second.emplace_back( schRef );
510
511 // Whole footprint was selected, no need to select pins
512 continue;
513 }
514
515 // Look for pins
516 auto symPinMatchIt = aSyncPinMap.find( fullRef );
517
518 if( symPinMatchIt != aSyncPinMap.end() )
519 {
520 std::unordered_map<wxString, SCH_PIN*>& pinMap = symPinMatchIt->second;
521 std::vector<SCH_PIN*> pinsOnSheet = symbol->GetPins( &aSheetPath );
522
523 for( SCH_PIN* pin : pinsOnSheet )
524 {
525 int pinUnit = pin->GetLibPin()->GetUnit();
526
527 if( pinUnit > 0 && pinUnit != schRef.GetUnit() )
528 continue;
529
530 auto pinIt = pinMap.find( pin->GetNumber() );
531
532 if( pinIt != pinMap.end() )
533 pinIt->second = pin;
534 }
535 }
536 }
537
538 return false;
539}
540
541
543 const SCH_SHEET_LIST& aSchematicSheetList, const SCH_SHEET_PATH& aSheetPath,
544 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
545 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
546 std::unordered_map<SCH_SHEET_PATH, bool>& aCache )
547{
548 auto cacheIt = aCache.find( aSheetPath );
549
550 if( cacheIt != aCache.end() )
551 return cacheIt->second;
552
553 // Iterate over children
554 for( const SCH_SHEET_PATH& candidate : aSchematicSheetList )
555 {
556 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
557 continue;
558
559 bool childRet = sheetContainsOnlyWantedItems( aSchematicSheetList, candidate, aSyncSymMap,
560 aSyncPinMap, aCache );
561
562 if( !childRet )
563 {
564 aCache.emplace( aSheetPath, false );
565 return false;
566 }
567 }
568
569 SCH_REFERENCE_LIST references;
570 aSheetPath.GetSymbols( references, false, true );
571
572 if( references.GetCount() == 0 ) // Empty sheet, obviously do not contain wanted items
573 {
574 aCache.emplace( aSheetPath, false );
575 return false;
576 }
577
578 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
579 {
580 SCH_REFERENCE& schRef = references[ii];
581
582 if( schRef.IsSplitNeeded() )
583 schRef.Split();
584
585 wxString refNum = schRef.GetRefNumber();
586 wxString fullRef = schRef.GetRef() + refNum;
587
588 // Skip power symbols
589 if( fullRef.StartsWith( wxS( "#" ) ) )
590 continue;
591
592 // Unannotated symbols are not supported
593 if( refNum.compare( wxS( "?" ) ) == 0 )
594 continue;
595
596 if( aSyncSymMap.find( fullRef ) == aSyncSymMap.end() )
597 {
598 aCache.emplace( aSheetPath, false );
599 return false; // Some symbol is not wanted.
600 }
601
602 if( aSyncPinMap.find( fullRef ) != aSyncPinMap.end() )
603 {
604 aCache.emplace( aSheetPath, false );
605 return false; // Looking for specific pins, so can't be mapped
606 }
607 }
608
609 aCache.emplace( aSheetPath, true );
610 return true;
611}
612
613
614std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>>
615findItemsFromSyncSelection( const SCHEMATIC& aSchematic, const std::string aSyncStr,
616 bool aFocusOnFirst )
617{
618 wxArrayString syncArray = wxStringTokenize( aSyncStr, wxS( "," ) );
619
620 std::unordered_map<wxString, std::vector<SCH_REFERENCE>> syncSymMap;
621 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>> syncPinMap;
622 std::unordered_map<SCH_SHEET_PATH, double> symScores;
623 std::unordered_map<SCH_SHEET_PATH, bool> fullyWantedCache;
624
625 std::optional<wxString> focusSymbol;
626 std::optional<std::pair<wxString, wxString>> focusPin;
627 std::unordered_map<SCH_SHEET_PATH, std::vector<SCH_ITEM*>> focusItemResults;
628
629 const SCH_SHEET_LIST allSheetsList = aSchematic.Hierarchy();
630
631 // In orderedSheets, the current sheet comes first.
632 std::vector<SCH_SHEET_PATH> orderedSheets;
633 orderedSheets.reserve( allSheetsList.size() );
634 orderedSheets.push_back( aSchematic.CurrentSheet() );
635
636 for( const SCH_SHEET_PATH& sheetPath : allSheetsList )
637 {
638 if( sheetPath != aSchematic.CurrentSheet() )
639 orderedSheets.push_back( sheetPath );
640 }
641
642 // Init sync maps from the sync string
643 for( size_t i = 0; i < syncArray.size(); i++ )
644 {
645 wxString syncEntry = syncArray[i];
646
647 if( syncEntry.empty() )
648 continue;
649
650 wxString syncData = syncEntry.substr( 1 );
651
652 switch( syncEntry.GetChar( 0 ).GetValue() )
653 {
654 case 'F': // Select by footprint: F<Reference>
655 {
656 wxString symRef = UnescapeString( syncData );
657
658 if( aFocusOnFirst && ( i == 0 ) )
659 focusSymbol = symRef;
660
661 syncSymMap[symRef] = std::vector<SCH_REFERENCE>();
662 break;
663 }
664
665 case 'P': // Select by pad: P<Footprint reference>/<Pad number>
666 {
667 wxString symRef = UnescapeString( syncData.BeforeFirst( '/' ) );
668 wxString padNum = UnescapeString( syncData.AfterFirst( '/' ) );
669
670 if( aFocusOnFirst && ( i == 0 ) )
671 focusPin = std::make_pair( symRef, padNum );
672
673 syncPinMap[symRef][padNum] = nullptr;
674 break;
675 }
676
677 default:
678 break;
679 }
680 }
681
682 // Lambda definitions
683 auto flattenSyncMaps =
684 [&syncSymMap, &syncPinMap]() -> std::vector<SCH_ITEM*>
685 {
686 std::vector<SCH_ITEM*> allVec;
687
688 for( const auto& [symRef, symbols] : syncSymMap )
689 {
690 for( const SCH_REFERENCE& ref : symbols )
691 allVec.push_back( ref.GetSymbol() );
692 }
693
694 for( const auto& [symRef, pinMap] : syncPinMap )
695 {
696 for( const auto& [padNum, pin] : pinMap )
697 {
698 if( pin )
699 allVec.push_back( pin );
700 }
701 }
702
703 return allVec;
704 };
705
706 auto clearSyncMaps =
707 [&syncSymMap, &syncPinMap]()
708 {
709 for( auto& [symRef, symbols] : syncSymMap )
710 symbols.clear();
711
712 for( auto& [reference, pins] : syncPinMap )
713 {
714 for( auto& [number, pin] : pins )
715 pin = nullptr;
716 }
717 };
718
719 auto syncMapsValuesEmpty =
720 [&syncSymMap, &syncPinMap]() -> bool
721 {
722 for( const auto& [symRef, symbols] : syncSymMap )
723 {
724 if( symbols.size() > 0 )
725 return false;
726 }
727
728 for( const auto& [symRef, pins] : syncPinMap )
729 {
730 for( const auto& [padNum, pin] : pins )
731 {
732 if( pin )
733 return false;
734 }
735 }
736
737 return true;
738 };
739
740 auto checkFocusItems =
741 [&]( const SCH_SHEET_PATH& aSheet )
742 {
743 if( focusSymbol )
744 {
745 auto findIt = syncSymMap.find( *focusSymbol );
746
747 if( findIt != syncSymMap.end() )
748 {
749 if( findIt->second.size() > 0 )
750 focusItemResults[aSheet].push_back( findIt->second.front().GetSymbol() );
751 }
752 }
753 else if( focusPin )
754 {
755 auto findIt = syncPinMap.find( focusPin->first );
756
757 if( findIt != syncPinMap.end() )
758 {
759 if( findIt->second[focusPin->second] )
760 focusItemResults[aSheet].push_back( findIt->second[focusPin->second] );
761 }
762 }
763 };
764
765 auto makeRetForSheet =
766 [&]( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aFocusItem )
767 {
768 clearSyncMaps();
769
770 // Fill sync maps
771 findSymbolsAndPins( allSheetsList, aSheet, syncSymMap, syncPinMap );
772 std::vector<SCH_ITEM*> itemsVector = flattenSyncMaps();
773
774 // Add fully wanted sheets to vector
775 for( SCH_ITEM* item : aSheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
776 {
777 KIID_PATH kiidPath = aSheet.Path();
778 kiidPath.push_back( item->m_Uuid );
779
780 std::optional<SCH_SHEET_PATH> subsheetPath =
781 allSheetsList.GetSheetPathByKIIDPath( kiidPath );
782
783 if( !subsheetPath )
784 continue;
785
786 if( sheetContainsOnlyWantedItems( allSheetsList, *subsheetPath, syncSymMap,
787 syncPinMap, fullyWantedCache ) )
788 {
789 itemsVector.push_back( item );
790 }
791 }
792
793 return std::make_tuple( aSheet, aFocusItem, itemsVector );
794 };
795
796 if( aFocusOnFirst )
797 {
798 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
799 {
800 clearSyncMaps();
801
802 findSymbolsAndPins( allSheetsList, sheetPath, syncSymMap, syncPinMap );
803
804 checkFocusItems( sheetPath );
805 }
806
807 if( focusItemResults.size() > 0 )
808 {
809 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
810 {
811 const std::vector<SCH_ITEM*>& items = focusItemResults[sheetPath];
812
813 if( !items.empty() )
814 return makeRetForSheet( sheetPath, items.front() );
815 }
816 }
817 }
818 else
819 {
820 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
821 {
822 clearSyncMaps();
823
824 findSymbolsAndPins( allSheetsList, sheetPath, syncSymMap, syncPinMap );
825
826 if( !syncMapsValuesEmpty() )
827 {
828 // Something found on sheet
829 return makeRetForSheet( sheetPath, nullptr );
830 }
831 }
832 }
833
834 return std::nullopt;
835}
836
837
839{
840 std::string& payload = mail.GetPayload();
841
842 switch( mail.Command() )
843 {
845 {
846 std::stringstream ss( payload );
847 std::string file;
848
850 std::optional<LIBRARY_TABLE*> optTable =
852
853 wxCHECK_RET( optTable, "Could not load symbol lib table." );
854
855 LIBRARY_TABLE* table = *optTable;
856
857 while( std::getline( ss, file, '\n' ) )
858 {
859 if( file.empty() )
860 continue;
861
862 wxFileName fn( file );
864 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
865
866 if( type == SCH_IO_MGR::SCH_FILE_UNKNOWN )
867 {
868 wxLogTrace( "KIWAY", "Unknown file type: %s", fn.GetFullPath() );
869 continue;
870 }
871
872 pi.reset( SCH_IO_MGR::FindPlugin( type ) );
873
874 if( !table->HasRow( fn.GetName() ) )
875 {
876 LIBRARY_TABLE_ROW& row = table->InsertRow();
877 row.SetNickname( fn.GetName() );
878 row.SetURI( fn.GetFullPath() );
879 row.SetType( SCH_IO_MGR::ShowType( type ) );
880
881 table->Save().map_error(
882 []( const LIBRARY_ERROR& aError )
883 {
884 wxLogError( _( "Error saving project-specific library table:\n\n%s" ),
885 aError.message );
886 } );
887
889 adapter->LoadOne( fn.GetName() );
890 }
891 }
892
896
897 break;
898 }
899
900 case MAIL_CROSS_PROBE:
901 ExecuteRemoteCommand( payload.c_str() );
902 break;
903
904 case MAIL_SELECTION:
905 if( !eeconfig()->m_CrossProbing.on_selection )
906 break;
907
909
911 {
912 // $SELECT: 0,<spec1>,<spec2>,<spec3>
913 // Try to select specified items.
914
915 // $SELECT: 1,<spec1>,<spec2>,<spec3>
916 // Select and focus on <spec1> item, select other specified items that are on the
917 // same sheet.
918
919 std::string prefix = "$SELECT: ";
920
921 std::string paramStr = payload.substr( prefix.size() );
922
923 // Empty/broken command: we need at least 2 chars for sync string.
924 if( paramStr.size() < 2 )
925 break;
926
927 std::string syncStr = paramStr.substr( 2 );
928
929 bool focusOnFirst = ( paramStr[0] == '1' );
930
931 std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>> findRet =
932 findItemsFromSyncSelection( Schematic(), syncStr, focusOnFirst );
933
934 if( findRet )
935 {
936 auto& [sheetPath, focusItem, items] = *findRet;
937
938 m_syncingPcbToSchSelection = true; // recursion guard
939
940 GetToolManager()->GetTool<SCH_SELECTION_TOOL>()->SyncSelection( sheetPath, focusItem,
941 items );
942
944
945 if( eeconfig()->m_CrossProbing.flash_selection )
946 {
947 wxLogTrace( traceCrossProbeFlash, "MAIL_SELECTION(_FORCE): flash enabled, items=%zu", items.size() );
948 if( items.empty() )
949 {
950 wxLogTrace( traceCrossProbeFlash, "MAIL_SELECTION(_FORCE): nothing to flash" );
951 }
952 else
953 {
954 std::vector<SCH_ITEM*> itemPtrs;
955 std::copy( items.begin(), items.end(), std::back_inserter( itemPtrs ) );
956
957 StartCrossProbeFlash( itemPtrs );
958 }
959 }
960 else
961 {
962 wxLogTrace( traceCrossProbeFlash, "MAIL_SELECTION(_FORCE): flash disabled" );
963 }
964 }
965
966 break;
967 }
968
970 {
971 if( !payload.empty() )
972 {
973 wxString annotationMessage( payload );
974
975 // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
976 if( !ReadyToNetlist( annotationMessage ) )
977 return;
978 }
979
980 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
982
983 NETLIST_EXPORTER_KICAD exporter( &Schematic() );
984 STRING_FORMATTER formatter;
985
986 exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
987
988 payload = formatter.GetString();
989 break;
990 }
991
993 {
994 KIID uuid( payload );
996
997 if( SCH_ITEM* item = m_schematic->ResolveItem( uuid, &path, true ) )
998 {
999 if( item->Type() == SCH_SHEET_T )
1000 payload = static_cast<SCH_SHEET*>( item )->GetShownName( false );
1001 else if( item->Type() == SCH_SYMBOL_T )
1002 payload = static_cast<SCH_SYMBOL*>( item )->GetRef( &path, true );
1003 else
1004 payload = item->GetFriendlyName();
1005 }
1006
1007 break;
1008 }
1009
1011 try
1012 {
1013 SCH_EDITOR_CONTROL* controlTool = m_toolManager->GetTool<SCH_EDITOR_CONTROL>();
1014 controlTool->AssignFootprints( payload );
1015 }
1016 catch( const IO_ERROR& )
1017 {
1018 }
1019 break;
1020
1021 case MAIL_SCH_REFRESH:
1022 {
1024
1026 GetCanvas()->Refresh();
1027 break;
1028 }
1029
1030 case MAIL_IMPORT_FILE:
1031 {
1032 // Extract file format type and path (plugin type, path and properties keys, values
1033 // separated with \n)
1034 std::stringstream ss( payload );
1035 char delim = '\n';
1036
1037 std::string formatStr;
1038 wxCHECK( std::getline( ss, formatStr, delim ), /* void */ );
1039
1040 std::string fnameStr;
1041 wxCHECK( std::getline( ss, fnameStr, delim ), /* void */ );
1042
1043 int importFormat;
1044
1045 try
1046 {
1047 importFormat = std::stoi( formatStr );
1048 }
1049 catch( std::invalid_argument& )
1050 {
1051 wxFAIL;
1052 importFormat = -1;
1053 }
1054
1055 std::map<std::string, UTF8> props;
1056
1057 do
1058 {
1059 std::string key, value;
1060
1061 if( !std::getline( ss, key, delim ) )
1062 break;
1063
1064 std::getline( ss, value, delim ); // We may want an empty string as value
1065
1066 props.emplace( key, value );
1067
1068 } while( true );
1069
1070 if( importFormat >= 0 )
1071 importFile( fnameStr, importFormat, props.empty() ? nullptr : &props );
1072
1073 break;
1074 }
1075
1076 case MAIL_SCH_SAVE:
1077 if( SaveProject() )
1078 payload = "success";
1079
1080 break;
1081
1082 case MAIL_SCH_UPDATE:
1084 break;
1085
1086 case MAIL_RELOAD_LIB:
1087 m_designBlocksPane->RefreshLibs();
1088 SyncView();
1089 break;
1090
1091 default:;
1092
1093 }
1094}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
static TOOL_ACTION showSymbolLibTable
Definition actions.h:283
static TOOL_ACTION updateSchematicFromPcb
Definition actions.h:264
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CROSS_PROBING_SETTINGS m_CrossProbing
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:516
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:98
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition view.cpp:1561
Definition kiid.h:49
wxString AsString() const
Definition kiid.cpp:246
Carry a payload from one KIWAY_PLAYER to another within a PROJECT.
std::string & GetPayload()
Return the payload, which can be any text but it typically self identifying s-expression.
MAIL_T Command()
Returns the MAIL_T associated with this mail.
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:507
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
Generate the KiCad netlist format supported by Pcbnew.
void Format(OUTPUTFORMATTER *aOutputFormatter, int aCtl)
Output this s-expression netlist into aOutputFormatter.
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:130
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Holds all the data relating to one schematic.
Definition schematic.h:88
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:186
static TOOL_ACTION runERC
Inspection and Editing.
static TOOL_ACTION changeSheet
static TOOL_ACTION updateNetHighlighting
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
const std::vector< std::shared_ptr< SCH_CONNECTION > > AllMembers() const
wxString Name(bool aIgnoreSheet=false) const
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
void AssignFootprints(const std::string &aChangedSetOfReferences)
SCH_ITEM * FindSymbolAndItem(const wxString *aPath, const wxString *aReference, bool aSearchHierarchy, SCH_SEARCH_T aSearchType, const wxString &aSearchText)
Find a symbol in the schematic and an item in this symbol and select it.
bool ReadyToNetlist(const wxString &aAnnotateMessage)
Check if we are ready to write a netlist file for the current schematic.
bool m_syncingPcbToSchSelection
friend class SCH_EDITOR_CONTROL
void SendSelectItemsToPcb(const std::vector< EDA_ITEM * > &aItems, bool aForce)
Send items to board editor for selection.
void SendCrossProbeClearHighlight()
Tell Pcbnew to clear the existing highlighted net, if one exists.
SCHEMATIC * m_schematic
The currently loaded schematic.
SCH_SHEET_PATH & GetCurrentSheet() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr)
Generate the connection data for the entire schematic hierarchy.
SCHEMATIC & Schematic() const
void ExecuteRemoteCommand(const char *cmdline) override
Execute a remote command sent via a socket on port KICAD_SCH_PORT_SERVICE_NUMBER (which defaults to 4...
void RefreshNetNavigator(const NET_NAVIGATOR_ITEM_DATA *aSelection=nullptr)
SCH_DESIGN_BLOCK_PANE * m_designBlocksPane
bool importFile(const wxString &aFileName, int aFileType, const std::map< std::string, UTF8 > *aProperties=nullptr)
Load the given filename but sets the path to the current project path.
void SendCrossProbeNetName(const wxString &aNetName)
Send a net name to Pcbnew for highlighting.
void StartCrossProbeFlash(const std::vector< SCH_ITEM * > &aItems)
wxString m_highlightedConn
The highlighted net or bus or empty string.
void SetCrossProbeConnection(const SCH_CONNECTION *aConnection)
Send a connection (net or bus) to Pcbnew for highlighting.
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
bool SaveProject(bool aSaveAs=false)
Save the currently-open schematic (including its hierarchy) and associated project.
void KiwayMailIn(KIWAY_EXPRESS &aEvent) override
Receive KIWAY_EXPRESS messages from other players.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a symbol library using the file extension of aLibPath.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
int GetUnit() const
Definition sch_item.h:238
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
A helper to define a symbol's reference designator in a schematic.
void Split()
Attempt to split the reference designator into a name (U) and number (1).
bool IsSplitNeeded()
Determine if this reference needs to be split or if it likely already has been.
SCH_SYMBOL * GetSymbol() const
wxString GetRef() const
wxString GetRefNumber() const
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath, bool aIncludeLastSheet=true) const
Finds a SCH_SHEET_PATH that matches the provided KIID_PATH.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void GetSymbols(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanSymbols=false) const
Adds SCH_REFERENCE object to aReferences for each symbol in the sheet.
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
SCH_SCREEN * LastScreen()
bool IsContainedWithin(const SCH_SHEET_PATH &aSheetPathToTest) const
Check if this path is contained inside aSheetPathToTest.
wxString PathAsString() const
Return the path of time stamps which do not changes even when editing sheet parameters.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
Schematic symbol object.
Definition sch_symbol.h:76
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:450
const std::string & GetString()
Definition richio.h:473
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(const wxString &aNickname)
Loads or reloads the given library, if it exists.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
virtual const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const =0
TOOL_MANAGER * m_toolManager
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.
#define _(s)
bool SendCommand(int aService, const std::string &aMessage)
Used by a client to sent (by a socket connection) a data to a server.
Definition eda_dde.cpp:310
DDE server & client.
#define MSG_TO_PCB
Definition eda_dde.h:49
std::optional< std::tuple< SCH_SHEET_PATH, SCH_ITEM *, std::vector< SCH_ITEM * > > > findItemsFromSyncSelection(const SCHEMATIC &aSchematic, const std::string aSyncStr, bool aFocusOnFirst)
bool findSymbolsAndPins(const SCH_SHEET_LIST &aSchematicSheetList, const SCH_SHEET_PATH &aSheetPath, std::unordered_map< wxString, std::vector< SCH_REFERENCE > > &aSyncSymMap, std::unordered_map< wxString, std::unordered_map< wxString, SCH_PIN * > > &aSyncPinMap, bool aRecursive=false)
bool sheetContainsOnlyWantedItems(const SCH_SHEET_LIST &aSchematicSheetList, const SCH_SHEET_PATH &aSheetPath, std::unordered_map< wxString, std::vector< SCH_REFERENCE > > &aSyncSymMap, std::unordered_map< wxString, std::unordered_map< wxString, SCH_PIN * > > &aSyncPinMap, std::unordered_map< SCH_SHEET_PATH, bool > &aCache)
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:35
@ FRAME_SCH_VIEWER
Definition frame_type.h:36
@ FRAME_CVPCB
Definition frame_type.h:52
const wxChar *const traceCrossProbeFlash
Flag to enable debug output for cross-probe flash operations.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:623
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:83
@ MAIL_IMPORT_FILE
Definition mail_type.h:48
@ MAIL_SCH_REFRESH
Definition mail_type.h:53
@ MAIL_CROSS_PROBE
Definition mail_type.h:39
@ MAIL_SELECTION_FORCE
Definition mail_type.h:41
@ MAIL_SCH_SAVE
Definition mail_type.h:43
@ MAIL_ASSIGN_FOOTPRINTS
Definition mail_type.h:42
@ MAIL_SCH_GET_ITEM
Definition mail_type.h:50
@ MAIL_SCH_UPDATE
Definition mail_type.h:47
@ MAIL_ADD_LOCAL_LIB
Definition mail_type.h:54
@ MAIL_SCH_GET_NETLIST
Definition mail_type.h:49
@ MAIL_SELECTION
Definition mail_type.h:40
@ MAIL_RELOAD_LIB
Definition mail_type.h:57
@ ALL
All except INITIAL_ADD.
Definition view_item.h:59
#define GNL_ALL
@ GNL_OPT_KICAD
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
int StrPrintf(std::string *result, const char *format,...)
This is like sprintf() but the output is appended to a std::string instead of to a character array.
Definition richio.cpp:71
SCH_SEARCH_T
Schematic search type used by the socket link with Pcbnew.
@ HIGHLIGHT_SYMBOL
@ HIGHLIGHT_PIN
@ GLOBAL_CLEANUP
Definition schematic.h:77
KIWAY Kiway(KFCTL_STANDALONE)
wxString UnescapeString(const wxString &aSource)
wxString From_UTF8(const char *cstring)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
@ CTX_IPC
Cross-probing behavior.
bool on_selection
Synchronize the selection for multiple items too.
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off).
bool center_on_items
Automatically pan to cross-probed items.
bool auto_highlight
Automatically turn on highlight mode in the target frame.
wxString message
@ REFERENCE
Field Reference of part, i.e. "IC21".
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_SHEET_T
Definition typeinfo.h:179
@ SCH_PIN_T
Definition typeinfo.h:157