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