KiCad PCB EDA Suite
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-2022 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
186void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
187{
189 char line[1024];
190
191 strncpy( line, cmdline, sizeof( line ) - 1 );
192 line[ sizeof( line ) - 1 ] = '\0';
193
194 char* idcmd = strtok( line, " \n\r" );
195 char* text = strtok( nullptr, "\"\n\r" );
196
197 if( idcmd == nullptr )
198 return;
199
200 CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing;
201
202 if( strcmp( idcmd, "$NET:" ) == 0 )
203 {
204 if( !crossProbingSettings.auto_highlight )
205 return;
206
207 wxString netName = FROM_UTF8( text );
208
209 if( auto sg = Schematic().ConnectionGraph()->FindFirstSubgraphByName( netName ) )
210 m_highlightedConn = sg->m_driver_connection;
211 else
212 m_highlightedConn = nullptr;
213
215
216 SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) );
217 return;
218 }
219
220 if( strcmp( idcmd, "$CLEAR:" ) == 0 )
221 {
222 // Cross-probing is now done through selection so we no longer need a clear command
223 return;
224 }
225
226 if( !crossProbingSettings.on_selection )
227 return;
228
229 if( text == nullptr )
230 return;
231
232 if( strcmp( idcmd, "$PART:" ) != 0 )
233 return;
234
235 wxString part_ref = FROM_UTF8( text );
236
237 /* look for a complement */
238 idcmd = strtok( nullptr, " \n\r" );
239
240 if( idcmd == nullptr ) // Highlight symbol only (from CvPcb or Pcbnew)
241 {
242 // Highlight symbol part_ref, or clear Highlight, if part_ref is not existing
243 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
244 return;
245 }
246
247 text = strtok( nullptr, "\"\n\r" );
248
249 if( text == nullptr )
250 return;
251
252 wxString msg = FROM_UTF8( text );
253
254 if( strcmp( idcmd, "$REF:" ) == 0 )
255 {
256 // Highlighting the reference itself isn't actually that useful, and it's harder to
257 // see. Highlight the parent and display the message.
258 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
259 }
260 else if( strcmp( idcmd, "$VAL:" ) == 0 )
261 {
262 // Highlighting the value itself isn't actually that useful, and it's harder to see.
263 // Highlight the parent and display the message.
264 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
265 }
266 else if( strcmp( idcmd, "$PAD:" ) == 0 )
267 {
268 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_PIN, msg );
269 }
270 else
271 {
272 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
273 }
274}
275
276
277void SCH_EDIT_FRAME::SendSelectItemsToPcb( const std::vector<EDA_ITEM*>& aItems, bool aForce )
278{
279 std::vector<wxString> parts;
280
281 for( EDA_ITEM* item : aItems )
282 {
283 switch( item->Type() )
284 {
285 case SCH_SYMBOL_T:
286 {
287 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
288
289 wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
290
291 parts.push_back( wxT( "F" ) + EscapeString( ref, CTX_IPC ) );
292
293 break;
294 }
295
296 case SCH_SHEET_T:
297 {
298 // For cross probing, we need the full path of the sheet, because
299 // we search by the footprint path prefix in the PCB editor
300
301 wxString full_path = GetCurrentSheet().PathAsString() + item->m_Uuid.AsString();
302
303 parts.push_back( wxT( "S" ) + full_path );
304
305 break;
306 }
307
308 case SCH_PIN_T:
309 {
310 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
311 SCH_SYMBOL* symbol = pin->GetParentSymbol();
312
313 wxString ref = symbol->GetField( REFERENCE_FIELD )->GetText();
314
315 parts.push_back( wxT( "P" ) + EscapeString( ref, CTX_IPC ) + wxT( "/" )
316 + EscapeString( pin->GetShownNumber(), CTX_IPC ) );
317
318 break;
319 }
320
321 default: break;
322 }
323 }
324
325 if( parts.empty() )
326 {
327 return;
328 }
329
330 std::string command = "$SELECT: 0,";
331
332 for( wxString part : parts )
333 {
334 command += part;
335 command += ",";
336 }
337
338 command.pop_back();
339
340 if( Kiface().IsSingle() )
341 {
342 SendCommand( MSG_TO_PCB, command );
343 }
344 else
345 {
346 // Typically ExpressMail is going to be s-expression packets, but since
347 // we have existing interpreter of the selection packet on the other
348 // side in place, we use that here.
350 command, this );
351 }
352}
353
354
355void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
356{
357 // The command is a keyword followed by a quoted string.
358
359 std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
360
361 if( !packet.empty() )
362 {
363 if( Kiface().IsSingle() )
364 {
365 SendCommand( MSG_TO_PCB, packet );
366 }
367 else
368 {
369 // Typically ExpressMail is going to be s-expression packets, but since
370 // we have existing interpreter of the cross probe packet on the other
371 // side in place, we use that here.
373 }
374 }
375}
376
377
379{
380 if( !aConnection )
381 {
383 return;
384 }
385
386 if( aConnection->IsNet() )
387 {
388 SendCrossProbeNetName( aConnection->Name() );
389 return;
390 }
391
392 if( aConnection->Members().empty() )
393 return;
394
395 auto all_members = aConnection->AllMembers();
396
397 wxString nets = all_members[0]->Name();
398
399 if( all_members.size() == 1 )
400 {
401 SendCrossProbeNetName( nets );
402 return;
403 }
404
405 // TODO: This could be replaced by just sending the bus name once we have bus contents
406 // included as part of the netlist sent from Eeschema to Pcbnew (and thus Pcbnew can
407 // natively keep track of bus membership)
408
409 for( size_t i = 1; i < all_members.size(); i++ )
410 nets << "," << all_members[i]->Name();
411
412 std::string packet = StrPrintf( "$NETS: \"%s\"", TO_UTF8( nets ) );
413
414 if( !packet.empty() )
415 {
416 if( Kiface().IsSingle() )
417 SendCommand( MSG_TO_PCB, packet );
418 else
419 {
420 // Typically ExpressMail is going to be s-expression packets, but since
421 // we have existing interpreter of the cross probe packet on the other
422 // side in place, we use that here.
424 }
425 }
426}
427
428
430{
431 std::string packet = "$CLEAR\n";
432
433 if( Kiface().IsSingle() )
434 {
435 SendCommand( MSG_TO_PCB, packet );
436 }
437 else
438 {
439 // Typically ExpressMail is going to be s-expression packets, but since
440 // we have existing interpreter of the cross probe packet on the other
441 // side in place, we use that here.
443 }
444}
445
446
448 const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
449 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
450 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
451 bool aRecursive = false )
452{
453 if( aRecursive )
454 {
455 // Iterate over children
456 for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
457 {
458 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
459 continue;
460
461 findSymbolsAndPins( aSchematic, candidate, aSyncSymMap, aSyncPinMap, aRecursive );
462 }
463 }
464
465 SCH_REFERENCE_LIST references;
466
467 aSheetPath.GetSymbols( references, false, true );
468
469 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
470 {
471 SCH_REFERENCE& schRef = references[ii];
472
473 if( schRef.IsSplitNeeded() )
474 schRef.Split();
475
476 SCH_SYMBOL* symbol = schRef.GetSymbol();
477 wxString refNum = schRef.GetRefNumber();
478 wxString fullRef = schRef.GetRef() + refNum;
479
480 // Skip power symbols
481 if( fullRef.StartsWith( "#" ) )
482 continue;
483
484 // Unannotated symbols are not supported
485 if( refNum.compare( "?" ) == 0 )
486 continue;
487
488 // Look for whole footprint
489 auto symMatchIt = aSyncSymMap.find( fullRef );
490
491 if( symMatchIt != aSyncSymMap.end() )
492 {
493 symMatchIt->second.emplace_back( schRef );
494
495 // Whole footprint was selected, no need to select pins
496 continue;
497 }
498
499 // Look for pins
500 auto symPinMatchIt = aSyncPinMap.find( fullRef );
501
502 if( symPinMatchIt != aSyncPinMap.end() )
503 {
504 std::unordered_map<wxString, SCH_PIN*>& pinMap = symPinMatchIt->second;
505 std::vector<SCH_PIN*> pinsOnSheet = symbol->GetPins( &aSheetPath );
506
507 for( SCH_PIN* pin : pinsOnSheet )
508 {
509 int pinUnit = pin->GetLibPin()->GetUnit();
510
511 if( pinUnit > 0 && pinUnit != schRef.GetUnit() )
512 continue;
513
514 auto pinIt = pinMap.find( pin->GetNumber() );
515
516 if( pinIt != pinMap.end() )
517 pinIt->second = pin;
518 }
519 }
520 }
521
522 return false;
523}
524
525
527 const SCHEMATIC& aSchematic, const SCH_SHEET_PATH& aSheetPath,
528 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
529 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
530 std::unordered_map<SCH_SHEET_PATH, bool>& aCache )
531{
532 auto cacheIt = aCache.find( aSheetPath );
533
534 if( cacheIt != aCache.end() )
535 return cacheIt->second;
536
537 // Iterate over children
538 for( const SCH_SHEET_PATH& candidate : aSchematic.GetSheets() )
539 {
540 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
541 continue;
542
543 bool childRet = sheetContainsOnlyWantedItems( aSchematic, candidate, aSyncSymMap,
544 aSyncPinMap, aCache );
545
546 if( !childRet )
547 {
548 aCache.emplace( aSheetPath, false );
549 return false;
550 }
551 }
552
553 SCH_REFERENCE_LIST references;
554 aSheetPath.GetSymbols( references, false, true );
555
556 if( references.GetCount() == 0 ) // Empty sheet, obviously do not contain wanted items
557 {
558 aCache.emplace( aSheetPath, false );
559 return false;
560 }
561
562 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
563 {
564 SCH_REFERENCE& schRef = references[ii];
565
566 if( schRef.IsSplitNeeded() )
567 schRef.Split();
568
569 wxString refNum = schRef.GetRefNumber();
570 wxString fullRef = schRef.GetRef() + refNum;
571
572 // Skip power symbols
573 if( fullRef.StartsWith( "#" ) )
574 continue;
575
576 // Unannotated symbols are not supported
577 if( refNum.compare( "?" ) == 0 )
578 continue;
579
580 if( aSyncSymMap.find( fullRef ) == aSyncSymMap.end() )
581 {
582 aCache.emplace( aSheetPath, false );
583 return false; // Some symbol is not wanted.
584 }
585
586 if( aSyncPinMap.find( fullRef ) != aSyncPinMap.end() )
587 {
588 aCache.emplace( aSheetPath, false );
589 return false; // Looking for specific pins, so can't be mapped
590 }
591 }
592
593 aCache.emplace( aSheetPath, true );
594 return true;
595}
596
597
598std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>>
599findItemsFromSyncSelection( const SCHEMATIC& aSchematic, const std::string aSyncStr,
600 bool aFocusOnFirst )
601{
602 wxArrayString syncArray = wxStringTokenize( aSyncStr, "," );
603
604 std::unordered_map<wxString, std::vector<SCH_REFERENCE>> syncSymMap;
605 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>> syncPinMap;
606 std::unordered_map<SCH_SHEET_PATH, double> symScores;
607 std::unordered_map<SCH_SHEET_PATH, bool> fullyWantedCache;
608
609 std::optional<wxString> focusSymbol;
610 std::optional<std::pair<wxString, wxString>> focusPin;
611 std::unordered_map<SCH_SHEET_PATH, std::vector<SCH_ITEM*>> focusItemResults;
612
613 const SCH_SHEET_LIST allSheetsList = aSchematic.GetSheets();
614
615 // In orderedSheets, the current sheet comes first.
616 SCH_SHEET_PATHS orderedSheets;
617 orderedSheets.reserve( allSheetsList.size() );
618 orderedSheets.push_back( aSchematic.CurrentSheet() );
619
620 for( const SCH_SHEET_PATH& sheetPath : allSheetsList )
621 {
622 if( sheetPath != aSchematic.CurrentSheet() )
623 orderedSheets.push_back( sheetPath );
624 }
625
626 // Init sync maps from the sync string
627 for( size_t i = 0; i < syncArray.size(); i++ )
628 {
629 wxString syncEntry = syncArray[i];
630
631 if( syncEntry.empty() )
632 continue;
633
634 wxString syncData = syncEntry.substr( 1 );
635
636 switch( syncEntry.GetChar( 0 ).GetValue() )
637 {
638 case 'F': // Select by footprint: F<Reference>
639 {
640 wxString symRef = UnescapeString( syncData );
641
642 if( aFocusOnFirst && ( i == 0 ) )
643 focusSymbol = symRef;
644
645 syncSymMap[symRef] = std::vector<SCH_REFERENCE>();
646 break;
647 }
648 case 'P': // Select by pad: P<Footprint reference>/<Pad number>
649 {
650 wxString symRef = UnescapeString( syncData.BeforeFirst( '/' ) );
651 wxString padNum = UnescapeString( syncData.AfterFirst( '/' ) );
652
653 if( aFocusOnFirst && ( i == 0 ) )
654 focusPin = std::make_pair( symRef, padNum );
655
656 syncPinMap[symRef][padNum] = nullptr;
657 break;
658 }
659 default: break;
660 }
661 }
662
663 // Lambda definitions
664 auto flattenSyncMaps = [&syncSymMap, &syncPinMap]() -> std::vector<SCH_ITEM*>
665 {
666 std::vector<SCH_ITEM*> allVec;
667
668 for( auto const& pairSym : syncSymMap )
669 {
670 for( const SCH_REFERENCE& ref : pairSym.second )
671 {
672 allVec.push_back( ref.GetSymbol() );
673 }
674 }
675
676 for( auto const& pairSym : syncPinMap )
677 {
678 for( auto const& pairPin : pairSym.second )
679 {
680 if( pairPin.second )
681 allVec.push_back( pairPin.second );
682 }
683 }
684
685 return allVec;
686 };
687
688 auto clearSyncMaps = [&syncSymMap, &syncPinMap]()
689 {
690 for( auto& pairSym : syncSymMap )
691 {
692 pairSym.second.clear();
693 }
694
695 for( auto& pairSym : syncPinMap )
696 {
697 for( auto& pairPin : pairSym.second )
698 {
699 pairPin.second = nullptr;
700 }
701 }
702 };
703
704 auto syncMapsValuesEmpty = [&syncSymMap, &syncPinMap]() -> bool
705 {
706 for( auto const& pairSym : syncSymMap )
707 {
708 if( pairSym.second.size() > 0 )
709 return false;
710 }
711
712 for( auto const& pairSym : syncPinMap )
713 {
714 for( auto const& pairPin : pairSym.second )
715 {
716 if( pairPin.second )
717 return false;
718 }
719 }
720
721 return true;
722 };
723
724 auto checkFocusItems = [&]( const SCH_SHEET_PATH& aSheetPath )
725 {
726 if( focusSymbol )
727 {
728 auto findIt = syncSymMap.find( *focusSymbol );
729 if( findIt != syncSymMap.end() )
730 {
731 if( findIt->second.size() > 0 )
732 {
733 focusItemResults[aSheetPath].push_back( findIt->second.front().GetSymbol() );
734 }
735 }
736 }
737 else if( focusPin )
738 {
739 auto findIt = syncPinMap.find( focusPin->first );
740 if( findIt != syncPinMap.end() )
741 {
742 if( findIt->second[focusPin->second] )
743 {
744 focusItemResults[aSheetPath].push_back( findIt->second[focusPin->second] );
745 }
746 }
747 }
748 };
749
750 auto makeRetForSheet = [&]( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aFocusItem )
751 {
752 clearSyncMaps();
753
754 // Fill sync maps
755 findSymbolsAndPins( aSchematic, aSheet, syncSymMap, syncPinMap );
756 std::vector<SCH_ITEM*> itemsVector = flattenSyncMaps();
757
758 // Add fully wanted sheets to vector
759 for( SCH_ITEM* item : aSheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
760 {
761 KIID_PATH kiidPath = aSheet.Path();
762 kiidPath.push_back( item->m_Uuid );
763
764 std::optional<SCH_SHEET_PATH> subsheetPath =
765 allSheetsList.GetSheetPathByKIIDPath( kiidPath );
766
767 if( !subsheetPath )
768 continue;
769
770 if( sheetContainsOnlyWantedItems( aSchematic, *subsheetPath, syncSymMap, syncPinMap,
771 fullyWantedCache ) )
772 {
773 itemsVector.push_back( item );
774 }
775 }
776
777 return std::make_tuple( aSheet, aFocusItem, itemsVector );
778 };
779
780 if( aFocusOnFirst )
781 {
782 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
783 {
784 clearSyncMaps();
785
786 findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
787
788 checkFocusItems( sheetPath );
789 }
790
791 if( focusItemResults.size() > 0 )
792 {
793 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
794 {
795 auto vec = focusItemResults[sheetPath];
796
797 if( !vec.empty() )
798 return makeRetForSheet( sheetPath, vec.front() );
799 }
800 }
801 }
802 else
803 {
804 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
805 {
806 clearSyncMaps();
807
808 findSymbolsAndPins( aSchematic, sheetPath, syncSymMap, syncPinMap );
809
810 if( !syncMapsValuesEmpty() )
811 {
812 // Something found on sheet
813 return makeRetForSheet( sheetPath, nullptr );
814 }
815 }
816 }
817
818 return std::nullopt;
819}
820
821
823{
824 std::string& payload = mail.GetPayload();
825
826 switch( mail.Command() )
827 {
828 case MAIL_CROSS_PROBE:
829 ExecuteRemoteCommand( payload.c_str() );
830 break;
831
832 case MAIL_SELECTION:
833 if( !eeconfig()->m_CrossProbing.on_selection )
834 break;
835
837
839 {
840 // $SELECT: 0,<spec1>,<spec2>,<spec3>
841 // Try to select specified items.
842
843 // $SELECT: 1,<spec1>,<spec2>,<spec3>
844 // Select and focus on <spec1> item, select other specified items that are on the same sheet.
845
846 std::string prefix = "$SELECT: ";
847
848 std::string paramStr = payload.substr( prefix.size() );
849
850 if( paramStr.size() < 2 ) // Empty/broken command: we need at least 2 chars for sync string.
851 break;
852
853 std::string syncStr = paramStr.substr( 2 );
854
855 bool focusOnFirst = ( paramStr[0] == '1' );
856
857 std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>> findRet =
858 findItemsFromSyncSelection( Schematic(), syncStr, focusOnFirst );
859
860 if( findRet )
861 {
862 auto& [sheetPath, focusItem, items] = *findRet;
863
864 m_syncingPcbToSchSelection = true; // recursion guard
865
866 GetToolManager()->GetTool<EE_SELECTION_TOOL>()->SyncSelection( sheetPath, focusItem,
867 items );
868
870 }
871
872 break;
873 }
874
876 {
877 if( !payload.empty() )
878 {
879 wxString annotationMessage( payload );
880
881 // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
882 if( !ReadyToNetlist( annotationMessage ) )
883 return;
884 }
885
886 NETLIST_EXPORTER_KICAD exporter( &Schematic() );
887 STRING_FORMATTER formatter;
888
889 // TODO remove once real-time connectivity is a given
890 if( !ADVANCED_CFG::GetCfg().m_RealTimeConnectivity || !CONNECTION_GRAPH::m_allowRealTime )
891 // Ensure the netlist data is up to date:
893
894 exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
895
896 payload = formatter.GetString();
897 }
898 break;
899
901 try
902 {
904 controlTool->AssignFootprints( payload );
905 }
906 catch( const IO_ERROR& )
907 {
908 }
909 break;
910
911 case MAIL_SCH_REFRESH:
912 {
914
916 GetCanvas()->Refresh();
917 }
918 break;
919
920 case MAIL_IMPORT_FILE:
921 {
922 // Extract file format type and path (plugin type and path separated with \n)
923 size_t split = payload.find( '\n' );
924 wxCHECK( split != std::string::npos, /*void*/ );
925 int importFormat;
926
927 try
928 {
929 importFormat = std::stoi( payload.substr( 0, split ) );
930 }
931 catch( std::invalid_argument& )
932 {
933 wxFAIL;
934 importFormat = -1;
935 }
936
937 std::string path = payload.substr( split + 1 );
938 wxASSERT( !path.empty() );
939
940 if( importFormat >= 0 )
941 importFile( path, importFormat );
942 }
943 break;
944
945 case MAIL_SCH_SAVE:
946 if( SaveProject() )
947 payload = "success";
948
949 break;
950
951 case MAIL_SCH_UPDATE:
953 break;
954
955 default:;
956
957 }
958}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION updateSchematicFromPcb
Definition: actions.h:167
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:170
static bool m_allowRealTime
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
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:492
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
static TOOL_ACTION updateNetHighlighting
Definition: ee_actions.h:254
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:105
void UpdateAllItems(int aUpdateFlags)
Update all items in the view according to the given flags.
Definition: view.cpp:1478
wxString AsString() const
Definition: kiid.cpp:249
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
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:53
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr)
Send aPayload to aDestination from aSource.
Definition: kiway.cpp:488
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:60
SCH_SHEET_PATH & CurrentSheet() const override
Definition: schematic.h:119
void SetCurrentSheet(const SCH_SHEET_PATH &aPath) override
Definition: schematic.h:124
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:85
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
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
std::vector< std::shared_ptr< SCH_CONNECTION > > & Members()
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)
Sends items to Pcbnew 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 by Pcbnew via a socket connection.
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
void SendCrossProbeNetName(const wxString &aNetName)
Sends 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.
const SCH_CONNECTION * m_highlightedConn
The highlighted net or bus, or nullptr.
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:108
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::optional< SCH_SHEET_PATH > GetSheetPathByKIIDPath(const KIID_PATH &aPath) 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:79
int GetUnit() const
Definition: sch_symbol.h:225
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
Definition: sch_symbol.cpp:516
SCH_FIELD * GetField(MANDATORY_FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:776
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:972
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
VECTOR2I GetPosition() const override
Definition: sch_symbol.h:707
SCH_PIN * GetPin(const wxString &number) const
Find a symbol pin by number.
Definition: sch_symbol.cpp:937
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:415
const std::string & GetString()
Definition: richio.h:438
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:214
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
#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
@ 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:84
@ NO_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:56
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:296
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:155
@ SCH_SHEET_T
Definition: typeinfo.h:157
@ SCH_PIN_T
Definition: typeinfo.h:158