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 (C) 2004-2023 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_express.h>
28#include <eda_dde.h>
29#include <connection_graph.h>
30#include <sch_sheet.h>
31#include <sch_symbol.h>
32#include <sch_reference_list.h>
33#include <schematic.h>
34#include <reporter.h>
35#include <string_utils.h>
39#include <tools/ee_actions.h>
41#include <advanced_config.h>
42#include <netclass.h>
43#include <wx/log.h>
44
45SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wxString* aReference,
46 bool aSearchHierarchy, SCH_SEARCH_T aSearchType,
47 const wxString& aSearchText )
48{
49 SCH_SHEET_PATH* sheetWithSymbolFound = nullptr;
50 SCH_SYMBOL* symbol = nullptr;
51 VECTOR2I pos;
52 SCH_PIN* pin = nullptr;
53 SCH_SHEET_LIST sheetList;
54 SCH_ITEM* foundItem = nullptr;
55
56 if( !aSearchHierarchy )
57 sheetList.push_back( m_frame->GetCurrentSheet() );
58 else
59 sheetList = m_frame->Schematic().GetSheets();
60
61 for( SCH_SHEET_PATH& sheet : sheetList )
62 {
63 SCH_SCREEN* screen = sheet.LastScreen();
64
65 for( EDA_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
66 {
67 SCH_SYMBOL* candidate = static_cast<SCH_SYMBOL*>( item );
68
69 // Search by path if specified, otherwise search by reference
70 bool found = false;
71
72 if( aPath )
73 {
74 wxString path = sheet.PathAsString() + candidate->m_Uuid.AsString();
75 found = ( *aPath == path );
76 }
77 else
78 {
79 found = ( aReference && aReference->CmpNoCase( candidate->GetRef( &sheet ) ) == 0 );
80 }
81
82 if( found )
83 {
84 symbol = candidate;
85 sheetWithSymbolFound = &sheet;
86
87 if( aSearchType == HIGHLIGHT_PIN )
88 {
89 // temporary: will be changed if the pin is found.
90 pos = symbol->GetPosition();
91 pin = symbol->GetPin( aSearchText );
92
93 // Ensure we have found the right unit in case of multi-units symbol
94 if( pin )
95 {
96 int unit = pin->GetLibPin()->GetUnit();
97
98 if( unit != 0 && unit != symbol->GetUnit() )
99 {
100 pin = nullptr;
101 continue;
102 }
103
104 // Get pin position in true schematic coordinate
105 pos = pin->GetPosition();
106 foundItem = pin;
107 break;
108 }
109 }
110 else
111 {
112 pos = symbol->GetPosition();
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
126 if( symbol )
127 {
128 if( *sheetWithSymbolFound != m_frame->GetCurrentSheet() )
129 {
130 m_frame->Schematic().SetCurrentSheet( *sheetWithSymbolFound );
132 }
133
134 if( crossProbingSettings.center_on_items )
135 {
136 if( crossProbingSettings.zoom_to_fit )
137 {
138 BOX2I bbox = symbol->GetBoundingBox();
139
140 m_toolMgr->GetTool<EE_SELECTION_TOOL>()->ZoomFitCrossProbeBBox( bbox );
141 }
142
143 if( pin )
145 else
146 m_frame->FocusOnItem( symbol );
147 }
148 }
149
150 /* Print diag */
151 wxString msg;
152 wxString displayRef;
153
154 if( aReference )
155 displayRef = *aReference;
156 else if( aPath )
157 displayRef = *aPath;
158
159 if( symbol )
160 {
161 if( aSearchType == HIGHLIGHT_PIN )
162 {
163 if( foundItem )
164 msg.Printf( _( "%s pin %s found" ), displayRef, aSearchText );
165 else
166 msg.Printf( _( "%s found but pin %s not found" ), displayRef, aSearchText );
167 }
168 else
169 {
170 msg.Printf( _( "%s found" ), displayRef );
171 }
172 }
173 else
174 {
175 msg.Printf( _( "%s not found" ), displayRef );
176 }
177
178 m_frame->SetStatusText( msg );
179
181
182 return foundItem;
183}
184
185
186/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
187 *
188 * Commands are:
189 *
190 * $PART: "reference" Put cursor on symbol.
191 * $PART: "reference" $REF: "ref" Put cursor on symbol reference.
192 * $PART: "reference" $VAL: "value" Put cursor on symbol value.
193 * $PART: "reference" $PAD: "pin name" Put cursor on the symbol pin.
194 * $NET: "netname" Highlight a specified net
195 * $CLEAR: "HIGHLIGHTED" Clear symbols highlight
196 *
197 * $CONFIG Show the Manage Symbol Libraries dialog
198 * $ERC Show the ERC dialog
199 */
200void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
201{
203 char line[1024];
204
205 strncpy( line, cmdline, sizeof( line ) - 1 );
206 line[ sizeof( line ) - 1 ] = '\0';
207
208 char* idcmd = strtok( line, " \n\r" );
209 char* text = strtok( nullptr, "\"\n\r" );
210
211 if( idcmd == nullptr )
212 return;
213
214 CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing;
215
216 if( strcmp( idcmd, "$CONFIG" ) == 0 )
217 {
219 return;
220 }
221 else if( strcmp( idcmd, "$ERC" ) == 0 )
222 {
224 return;
225 }
226 else if( strcmp( idcmd, "$NET:" ) == 0 )
227 {
228 if( !crossProbingSettings.auto_highlight )
229 return;
230
231 wxString netName = FROM_UTF8( text );
232
233 if( auto sg = Schematic().ConnectionGraph()->FindFirstSubgraphByName( netName ) )
234 m_highlightedConn = sg->GetDriverConnection()->Name();
235 else
236 m_highlightedConn = wxEmptyString;
237
239
240 SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) );
241 return;
242 }
243 else if( strcmp( idcmd, "$CLEAR:" ) == 0 )
244 {
245 // Cross-probing is now done through selection so we no longer need a clear command
246 return;
247 }
248
249 if( !crossProbingSettings.on_selection )
250 return;
251
252 if( text == nullptr )
253 return;
254
255 if( strcmp( idcmd, "$PART:" ) != 0 )
256 return;
257
258 wxString part_ref = FROM_UTF8( text );
259
260 /* look for a complement */
261 idcmd = strtok( nullptr, " \n\r" );
262
263 if( idcmd == nullptr ) // Highlight symbol only (from CvPcb or Pcbnew)
264 {
265 // Highlight symbol part_ref, or clear Highlight, if part_ref is not existing
266 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
267 return;
268 }
269
270 text = strtok( nullptr, "\"\n\r" );
271
272 if( text == nullptr )
273 return;
274
275 wxString msg = FROM_UTF8( text );
276
277 if( strcmp( idcmd, "$REF:" ) == 0 )
278 {
279 // Highlighting the reference itself isn't actually that useful, and it's harder to
280 // see. Highlight the parent and display the message.
281 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
282 }
283 else if( strcmp( idcmd, "$VAL:" ) == 0 )
284 {
285 // Highlighting the value itself isn't actually that useful, and it's harder to see.
286 // Highlight the parent and display the message.
287 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
288 }
289 else if( strcmp( idcmd, "$PAD:" ) == 0 )
290 {
291 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_PIN, msg );
292 }
293 else
294 {
295 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
296 }
297}
298
299
300void SCH_EDIT_FRAME::SendSelectItemsToPcb( const std::vector<EDA_ITEM*>& aItems, bool aForce )
301{
302 std::vector<wxString> parts;
303
304 for( EDA_ITEM* item : aItems )
305 {
306 switch( item->Type() )
307 {
308 case SCH_SYMBOL_T:
309 {
310 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
311
312 wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
313
314 parts.push_back( wxT( "F" ) + EscapeString( ref, CTX_IPC ) );
315
316 break;
317 }
318
319 case SCH_SHEET_T:
320 {
321 // For cross probing, we need the full path of the sheet, because
322 // we search by the footprint path prefix in the PCB editor
323
324 wxString full_path = GetCurrentSheet().PathAsString() + item->m_Uuid.AsString();
325
326 parts.push_back( wxT( "S" ) + full_path );
327
328 break;
329 }
330
331 case SCH_PIN_T:
332 {
333 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
334 SCH_SYMBOL* symbol = pin->GetParentSymbol();
335
336 wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
337
338 parts.push_back( wxT( "P" ) + EscapeString( ref, CTX_IPC ) + wxT( "/" )
339 + EscapeString( pin->GetShownNumber(), CTX_IPC ) );
340
341 break;
342 }
343
344 default: break;
345 }
346 }
347
348 if( parts.empty() )
349 {
350 return;
351 }
352
353 std::string command = "$SELECT: 0,";
354
355 for( wxString part : parts )
356 {
357 command += part;
358 command += ",";
359 }
360
361 command.pop_back();
362
363 if( Kiface().IsSingle() )
364 {
365 SendCommand( MSG_TO_PCB, command );
366 }
367 else
368 {
369 // Typically ExpressMail is going to be s-expression packets, but since
370 // we have existing interpreter of the selection packet on the other
371 // side in place, we use that here.
373 command, this );
374 }
375}
376
377
378void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
379{
380 // The command is a keyword followed by a quoted string.
381
382 std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
383
384 if( !packet.empty() )
385 {
386 if( Kiface().IsSingle() )
387 {
388 SendCommand( MSG_TO_PCB, packet );
389 }
390 else
391 {
392 // Typically ExpressMail is going to be s-expression packets, but since
393 // we have existing interpreter of the cross probe packet on the other
394 // side in place, we use that here.
396 }
397 }
398}
399
400
402{
403 if( !aConnection )
404 {
406 return;
407 }
408
409 if( aConnection->IsNet() )
410 {
411 SendCrossProbeNetName( aConnection->Name() );
412 return;
413 }
414
415 if( aConnection->Members().empty() )
416 return;
417
418 auto all_members = aConnection->AllMembers();
419
420 wxString nets = all_members[0]->Name();
421
422 if( all_members.size() == 1 )
423 {
424 SendCrossProbeNetName( nets );
425 return;
426 }
427
428 // TODO: This could be replaced by just sending the bus name once we have bus contents
429 // included as part of the netlist sent from Eeschema to Pcbnew (and thus Pcbnew can
430 // natively keep track of bus membership)
431
432 for( size_t i = 1; i < all_members.size(); i++ )
433 nets << "," << all_members[i]->Name();
434
435 std::string packet = StrPrintf( "$NETS: \"%s\"", TO_UTF8( nets ) );
436
437 if( !packet.empty() )
438 {
439 if( Kiface().IsSingle() )
440 SendCommand( MSG_TO_PCB, packet );
441 else
442 {
443 // Typically ExpressMail is going to be s-expression packets, but since
444 // we have existing interpreter of the cross probe packet on the other
445 // side in place, we use that here.
447 }
448 }
449}
450
451
453{
454 std::string packet = "$CLEAR\n";
455
456 if( Kiface().IsSingle() )
457 {
458 SendCommand( MSG_TO_PCB, packet );
459 }
460 else
461 {
462 // Typically ExpressMail is going to be s-expression packets, but since
463 // we have existing interpreter of the cross probe packet on the other
464 // side in place, we use that here.
466 }
467}
468
469
471 const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
472 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
473 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
474 bool aRecursive = false )
475{
476 if( aRecursive )
477 {
478 // Iterate over children
479 for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
480 {
481 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
482 continue;
483
484 findSymbolsAndPins( aSchematic, candidate, aSyncSymMap, aSyncPinMap, aRecursive );
485 }
486 }
487
488 SCH_REFERENCE_LIST references;
489
490 aSheetPath.GetSymbols( references, false, true );
491
492 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
493 {
494 SCH_REFERENCE& schRef = references[ii];
495
496 if( schRef.IsSplitNeeded() )
497 schRef.Split();
498
499 SCH_SYMBOL* symbol = schRef.GetSymbol();
500 wxString refNum = schRef.GetRefNumber();
501 wxString fullRef = schRef.GetRef() + refNum;
502
503 // Skip power symbols
504 if( fullRef.StartsWith( wxS( "#" ) ) )
505 continue;
506
507 // Unannotated symbols are not supported
508 if( refNum.compare( wxS( "?" ) ) == 0 )
509 continue;
510
511 // Look for whole footprint
512 auto symMatchIt = aSyncSymMap.find( fullRef );
513
514 if( symMatchIt != aSyncSymMap.end() )
515 {
516 symMatchIt->second.emplace_back( schRef );
517
518 // Whole footprint was selected, no need to select pins
519 continue;
520 }
521
522 // Look for pins
523 auto symPinMatchIt = aSyncPinMap.find( fullRef );
524
525 if( symPinMatchIt != aSyncPinMap.end() )
526 {
527 std::unordered_map<wxString, SCH_PIN*>& pinMap = symPinMatchIt->second;
528 std::vector<SCH_PIN*> pinsOnSheet = symbol->GetPins( &aSheetPath );
529
530 for( SCH_PIN* pin : pinsOnSheet )
531 {
532 int pinUnit = pin->GetLibPin()->GetUnit();
533
534 if( pinUnit > 0 && pinUnit != schRef.GetUnit() )
535 continue;
536
537 auto pinIt = pinMap.find( pin->GetNumber() );
538
539 if( pinIt != pinMap.end() )
540 pinIt->second = pin;
541 }
542 }
543 }
544
545 return false;
546}
547
548
550 const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
551 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
552 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
553 std::unordered_map<SCH_SHEET_PATH, bool>& aCache )
554{
555 auto cacheIt = aCache.find( aSheetPath );
556
557 if( cacheIt != aCache.end() )
558 return cacheIt->second;
559
560 // Iterate over children
561 for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
562 {
563 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
564 continue;
565
566 bool childRet = sheetContainsOnlyWantedItems( aSchematic, candidate, aSyncSymMap,
567 aSyncPinMap, aCache );
568
569 if( !childRet )
570 {
571 aCache.emplace( aSheetPath, false );
572 return false;
573 }
574 }
575
576 SCH_REFERENCE_LIST references;
577 aSheetPath.GetSymbols( references, false, true );
578
579 if( references.GetCount() == 0 ) // Empty sheet, obviously do not contain wanted items
580 {
581 aCache.emplace( aSheetPath, false );
582 return false;
583 }
584
585 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
586 {
587 SCH_REFERENCE& schRef = references[ii];
588
589 if( schRef.IsSplitNeeded() )
590 schRef.Split();
591
592 wxString refNum = schRef.GetRefNumber();
593 wxString fullRef = schRef.GetRef() + refNum;
594
595 // Skip power symbols
596 if( fullRef.StartsWith( wxS( "#" ) ) )
597 continue;
598
599 // Unannotated symbols are not supported
600 if( refNum.compare( wxS( "?" ) ) == 0 )
601 continue;
602
603 if( aSyncSymMap.find( fullRef ) == aSyncSymMap.end() )
604 {
605 aCache.emplace( aSheetPath, false );
606 return false; // Some symbol is not wanted.
607 }
608
609 if( aSyncPinMap.find( fullRef ) != aSyncPinMap.end() )
610 {
611 aCache.emplace( aSheetPath, false );
612 return false; // Looking for specific pins, so can't be mapped
613 }
614 }
615
616 aCache.emplace( aSheetPath, true );
617 return true;
618}
619
620
621std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>>
622findItemsFromSyncSelection( const SCHEMATIC& aSchematic, const std::string aSyncStr,
623 bool aFocusOnFirst )
624{
625 wxArrayString syncArray = wxStringTokenize( aSyncStr, wxS( "," ) );
626
627 std::unordered_map<wxString, std::vector<SCH_REFERENCE>> syncSymMap;
628 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>> syncPinMap;
629 std::unordered_map<SCH_SHEET_PATH, double> symScores;
630 std::unordered_map<SCH_SHEET_PATH, bool> fullyWantedCache;
631
632 std::optional<wxString> focusSymbol;
633 std::optional<std::pair<wxString, wxString>> focusPin;
634 std::unordered_map<SCH_SHEET_PATH, std::vector<SCH_ITEM*>> focusItemResults;
635
636 const SCH_SHEET_LIST allSheetsList = aSchematic.GetSheets();
637
638 // In orderedSheets, the current sheet comes first.
639 SCH_SHEET_PATHS orderedSheets;
640 orderedSheets.reserve( allSheetsList.size() );
641 orderedSheets.push_back( aSchematic.CurrentSheet() );
642
643 for( const SCH_SHEET_PATH& sheetPath : allSheetsList )
644 {
645 if( sheetPath != aSchematic.CurrentSheet() )
646 orderedSheets.push_back( sheetPath );
647 }
648
649 // Init sync maps from the sync string
650 for( size_t i = 0; i < syncArray.size(); i++ )
651 {
652 wxString syncEntry = syncArray[i];
653
654 if( syncEntry.empty() )
655 continue;
656
657 wxString syncData = syncEntry.substr( 1 );
658
659 switch( syncEntry.GetChar( 0 ).GetValue() )
660 {
661 case 'F': // Select by footprint: F<Reference>
662 {
663 wxString symRef = UnescapeString( syncData );
664
665 if( aFocusOnFirst && ( i == 0 ) )
666 focusSymbol = symRef;
667
668 syncSymMap[symRef] = std::vector<SCH_REFERENCE>();
669 break;
670 }
671 case 'P': // Select by pad: P<Footprint reference>/<Pad number>
672 {
673 wxString symRef = UnescapeString( syncData.BeforeFirst( '/' ) );
674 wxString padNum = UnescapeString( syncData.AfterFirst( '/' ) );
675
676 if( aFocusOnFirst && ( i == 0 ) )
677 focusPin = std::make_pair( symRef, padNum );
678
679 syncPinMap[symRef][padNum] = nullptr;
680 break;
681 }
682 default: break;
683 }
684 }
685
686 // Lambda definitions
687 auto flattenSyncMaps = [&syncSymMap, &syncPinMap]() -> std::vector<SCH_ITEM*>
688 {
689 std::vector<SCH_ITEM*> allVec;
690
691 for( auto const& pairSym : syncSymMap )
692 {
693 for( const SCH_REFERENCE& ref : pairSym.second )
694 {
695 allVec.push_back( ref.GetSymbol() );
696 }
697 }
698
699 for( auto const& pairSym : syncPinMap )
700 {
701 for( auto const& pairPin : pairSym.second )
702 {
703 if( pairPin.second )
704 allVec.push_back( pairPin.second );
705 }
706 }
707
708 return allVec;
709 };
710
711 auto clearSyncMaps = [&syncSymMap, &syncPinMap]()
712 {
713 for( auto& pairSym : syncSymMap )
714 {
715 pairSym.second.clear();
716 }
717
718 for( auto& pairSym : syncPinMap )
719 {
720 for( auto& pairPin : pairSym.second )
721 {
722 pairPin.second = nullptr;
723 }
724 }
725 };
726
727 auto syncMapsValuesEmpty = [&syncSymMap, &syncPinMap]() -> bool
728 {
729 for( auto const& pairSym : syncSymMap )
730 {
731 if( pairSym.second.size() > 0 )
732 return false;
733 }
734
735 for( auto const& pairSym : syncPinMap )
736 {
737 for( auto const& pairPin : pairSym.second )
738 {
739 if( pairPin.second )
740 return false;
741 }
742 }
743
744 return true;
745 };
746
747 auto checkFocusItems = [&]( const SCH_SHEET_PATH& aSheetPath )
748 {
749 if( focusSymbol )
750 {
751 auto findIt = syncSymMap.find( *focusSymbol );
752 if( findIt != syncSymMap.end() )
753 {
754 if( findIt->second.size() > 0 )
755 {
756 focusItemResults[aSheetPath].push_back( findIt->second.front().GetSymbol() );
757 }
758 }
759 }
760 else if( focusPin )
761 {
762 auto findIt = syncPinMap.find( focusPin->first );
763 if( findIt != syncPinMap.end() )
764 {
765 if( findIt->second[focusPin->second] )
766 {
767 focusItemResults[aSheetPath].push_back( findIt->second[focusPin->second] );
768 }
769 }
770 }
771 };
772
773 auto makeRetForSheet = [&]( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aFocusItem )
774 {
775 clearSyncMaps();
776
777 // Fill sync maps
778 findSymbolsAndPins( aSchematic, aSheet, syncSymMap, syncPinMap );
779 std::vector<SCH_ITEM*> itemsVector = flattenSyncMaps();
780
781 // Add fully wanted sheets to vector
782 for( SCH_ITEM* item : aSheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
783 {
784 KIID_PATH kiidPath = aSheet.Path();
785 kiidPath.push_back( item->m_Uuid );
786
787 std::optional<SCH_SHEET_PATH> subsheetPath =
788 allSheetsList.GetSheetPathByKIIDPath( kiidPath );
789
790 if( !subsheetPath )
791 continue;
792
793 if( sheetContainsOnlyWantedItems( aSchematic, *subsheetPath, syncSymMap, syncPinMap,
794 fullyWantedCache ) )
795 {
796 itemsVector.push_back( item );
797 }
798 }
799
800 return std::make_tuple( aSheet, aFocusItem, itemsVector );
801 };
802
803 if( aFocusOnFirst )
804 {
805 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
806 {
807 clearSyncMaps();
808
809 findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
810
811 checkFocusItems( sheetPath );
812 }
813
814 if( focusItemResults.size() > 0 )
815 {
816 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
817 {
818 auto vec = focusItemResults[sheetPath];
819
820 if( !vec.empty() )
821 return makeRetForSheet( sheetPath, vec.front() );
822 }
823 }
824 }
825 else
826 {
827 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
828 {
829 clearSyncMaps();
830
831 findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
832
833 if( !syncMapsValuesEmpty() )
834 {
835 // Something found on sheet
836 return makeRetForSheet( sheetPath, nullptr );
837 }
838 }
839 }
840
841 return std::nullopt;
842}
843
844
846{
847 std::string& payload = mail.GetPayload();
848
849 switch( mail.Command() )
850 {
851 case MAIL_CROSS_PROBE:
852 ExecuteRemoteCommand( payload.c_str() );
853 break;
854
855 case MAIL_SELECTION:
856 if( !eeconfig()->m_CrossProbing.on_selection )
857 break;
858
860
862 {
863 // $SELECT: 0,<spec1>,<spec2>,<spec3>
864 // Try to select specified items.
865
866 // $SELECT: 1,<spec1>,<spec2>,<spec3>
867 // Select and focus on <spec1> item, select other specified items that are on the same sheet.
868
869 std::string prefix = "$SELECT: ";
870
871 std::string paramStr = payload.substr( prefix.size() );
872
873 if( paramStr.size() < 2 ) // Empty/broken command: we need at least 2 chars for sync string.
874 break;
875
876 std::string syncStr = paramStr.substr( 2 );
877
878 bool focusOnFirst = ( paramStr[0] == '1' );
879
880 std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>> findRet =
881 findItemsFromSyncSelection( Schematic(), syncStr, focusOnFirst );
882
883 if( findRet )
884 {
885 auto& [sheetPath, focusItem, items] = *findRet;
886
887 m_syncingPcbToSchSelection = true; // recursion guard
888
889 GetToolManager()->GetTool<EE_SELECTION_TOOL>()->SyncSelection( sheetPath, focusItem,
890 items );
891
893 }
894
895 break;
896 }
897
899 {
900 if( !payload.empty() )
901 {
902 wxString annotationMessage( payload );
903
904 // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
905 if( !ReadyToNetlist( annotationMessage ) )
906 return;
907 }
908
909 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
911
912 NETLIST_EXPORTER_KICAD exporter( &Schematic() );
913 STRING_FORMATTER formatter;
914
915 exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
916
917 payload = formatter.GetString();
918 }
919 break;
920
922 try
923 {
925 controlTool->AssignFootprints( payload );
926 }
927 catch( const IO_ERROR& )
928 {
929 }
930 break;
931
932 case MAIL_SCH_REFRESH:
933 {
935
937 GetCanvas()->Refresh();
938 }
939 break;
940
941 case MAIL_IMPORT_FILE:
942 {
943 // Extract file format type and path (plugin type and path separated with \n)
944 size_t split = payload.find( '\n' );
945 wxCHECK( split != std::string::npos, /*void*/ );
946 int importFormat;
947
948 try
949 {
950 importFormat = std::stoi( payload.substr( 0, split ) );
951 }
952 catch( std::invalid_argument& )
953 {
954 wxFAIL;
955 importFormat = -1;
956 }
957
958 std::string path = payload.substr( split + 1 );
959 wxASSERT( !path.empty() );
960
961 if( importFormat >= 0 )
962 importFile( path, importFormat );
963 }
964 break;
965
966 case MAIL_SCH_SAVE:
967 if( SaveProject() )
968 payload = "success";
969
970 break;
971
972 case MAIL_SCH_UPDATE:
974 break;
975
976 case MAIL_RELOAD_LIB:
977 SyncView();
978 break;
979
980 default:;
981
982 }
983}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION showSymbolLibTable
Definition: actions.h:181
static TOOL_ACTION updateSchematicFromPcb
Definition: actions.h:169
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
CROSS_PROBING_SETTINGS m_CrossProbing
Definition: app_settings.h:173
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:85
const KIID m_Uuid
Definition: eda_item.h:475
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
static TOOL_ACTION runERC
Definition: ee_actions.h:151
static TOOL_ACTION updateNetHighlighting
Definition: ee_actions.h:285
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
bool IsSingle() const
Is this KIFACE running under single_top?
Definition: kiface_base.h:107
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1501
wxString AsString() const
Definition: kiid.cpp:257
Carry a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition: kiway_express.h:39
std::string & GetPayload()
Return the payload, which can be any text but it typically self identifying s-expression.
Definition: kiway_express.h:57
MAIL_T Command()
Returns the MAIL_T associated with this mail.
Definition: kiway_express.h:49
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:549
Generate the KiCad netlist format supported by Pcbnew.
void Format(OUTPUTFORMATTER *aOutputFormatter, int aCtl)
Output this s-expression netlist into aOutputFormatter.
Holds all the data relating to one schematic.
Definition: schematic.h:72
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:133
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:138
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:97
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.
Handle actions specific to the schematic editor.
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
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.
SCH_SHEET_PATH & GetCurrentSheet() const
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 RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
void SendCrossProbeNetName(const wxString &aNetName)
Send a net name to Pcbnew for highlighting.
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
void DisplayCurrentSheet()
Draw the current sheet on the display.
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 FocusOnItem(SCH_ITEM *aItem)
void KiwayMailIn(KIWAY_EXPRESS &aEvent) override
Receive KIWAY_EXPRESS messages from other players.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
size_t GetCount() const
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
int GetUnit() const
wxString GetRefNumber() const
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
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.
Schematic symbol object.
Definition: sch_symbol.h:81
int GetUnit() const
Definition: sch_symbol.h:231
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:698
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:891
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:726
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:427
const std::string & GetString()
Definition: richio.h:450
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:170
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:54
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:216
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:142
#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
bool findSymbolsAndPins(const SCHEMATIC &aSchematic, 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)
std::optional< std::tuple< SCH_SHEET_PATH, SCH_ITEM *, std::vector< SCH_ITEM * > > > findItemsFromSyncSelection(const SCHEMATIC &aSchematic, const std::string aSyncStr, bool aFocusOnFirst)
bool sheetContainsOnlyWantedItems(const SCHEMATIC &aSchematic, 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:40
KIWAY Kiway
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
@ MAIL_IMPORT_FILE
Definition: mail_type.h:48
@ MAIL_SCH_REFRESH
Definition: mail_type.h:52
@ 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_UPDATE
Definition: mail_type.h:47
@ MAIL_SCH_GET_NETLIST
Definition: mail_type.h:49
@ MAIL_SELECTION
Definition: mail_type.h:40
@ MAIL_RELOAD_LIB
Definition: mail_type.h:55
@ ALL
All except INITIAL_ADD.
Definition: view_item.h:53
#define GNL_ALL
@ GNL_OPT_KICAD
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:85
@ GLOBAL_CLEANUP
SCH_SEARCH_T
Schematic search type used by the socket link with Pcbnew.
@ HIGHLIGHT_SYMBOL
@ HIGHLIGHT_PIN
std::vector< SCH_SHEET_PATH > SCH_SHEET_PATHS
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_IPC
Definition: string_utils.h:57
static std::vector< std::string > split(const std::string &aStr, const std::string &aDelim)
Split the input string into a vector of output strings.
Definition: string_utils.h:297
Cross-probing behavior.
Definition: app_settings.h:31
bool on_selection
Synchronize the selection for multiple items too.
Definition: app_settings.h:32
bool zoom_to_fit
Zoom to fit items (ignored if center_on_items is off)
Definition: app_settings.h:34
bool center_on_items
Automatically pan to cross-probed items.
Definition: app_settings.h:33
bool auto_highlight
Automatically turn on highlight mode in the target frame.
Definition: app_settings.h:35
@ REFERENCE_FIELD
Field Reference of part, i.e. "IC21".
@ SCH_SYMBOL_T
Definition: typeinfo.h:146
@ SCH_SHEET_T
Definition: typeinfo.h:148
@ SCH_PIN_T
Definition: typeinfo.h:149