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