KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <stambaughw@gmail.com>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <kiface_base.h>
27#include <kiway.h>
28#include <kiway_express.h>
29#include <eda_dde.h>
30#include <connection_graph.h>
31#include <sch_sheet.h>
32#include <sch_symbol.h>
33#include <sch_reference_list.h>
34#include <string_utils.h>
38#include <project_sch.h>
39#include <richio.h>
40#include <symbol_lib_table.h>
41#include <tools/sch_actions.h>
43#include <advanced_config.h>
45#include <wx/log.h>
46
47SCH_ITEM* SCH_EDITOR_CONTROL::FindSymbolAndItem( const wxString* aPath, const wxString* aReference,
48 bool aSearchHierarchy, SCH_SEARCH_T aSearchType,
49 const wxString& aSearchText )
50{
51 SCH_SHEET_PATH* sheetWithSymbolFound = nullptr;
52 SCH_SYMBOL* symbol = nullptr;
53 SCH_PIN* pin = nullptr;
54 SCH_SHEET_LIST sheetList;
55 SCH_ITEM* foundItem = nullptr;
56
57 if( !aSearchHierarchy )
58 sheetList.push_back( m_frame->GetCurrentSheet() );
59 else
60 sheetList = m_frame->Schematic().Hierarchy();
61
62 for( SCH_SHEET_PATH& sheet : sheetList )
63 {
64 SCH_SCREEN* screen = sheet.LastScreen();
65
66 for( EDA_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
67 {
68 SCH_SYMBOL* candidate = static_cast<SCH_SYMBOL*>( item );
69
70 // Search by path if specified, otherwise search by reference
71 bool found = false;
72
73 if( aPath )
74 {
75 wxString path = sheet.PathAsString() + candidate->m_Uuid.AsString();
76 found = ( *aPath == path );
77 }
78 else
79 {
80 found = ( aReference && aReference->CmpNoCase( candidate->GetRef( &sheet ) ) == 0 );
81 }
82
83 if( found )
84 {
85 symbol = candidate;
86 sheetWithSymbolFound = &sheet;
87
88 if( aSearchType == HIGHLIGHT_PIN )
89 {
90 pin = symbol->GetPin( aSearchText );
91
92 // Ensure we have found the right unit in case of multi-units symbol
93 if( pin )
94 {
95 int unit = pin->GetLibPin()->GetUnit();
96
97 if( unit != 0 && unit != symbol->GetUnit() )
98 {
99 pin = nullptr;
100 continue;
101 }
102
103 // Get pin position in true schematic coordinate
104 foundItem = pin;
105 break;
106 }
107 }
108 else
109 {
110 foundItem = symbol;
111 break;
112 }
113 }
114 }
115
116 if( foundItem )
117 break;
118 }
119
120 CROSS_PROBING_SETTINGS& crossProbingSettings = m_frame->eeconfig()->m_CrossProbing;
121
122 if( symbol )
123 {
124 if( *sheetWithSymbolFound != m_frame->GetCurrentSheet() )
125 {
127 sheetWithSymbolFound );
128 }
129
130 if( crossProbingSettings.center_on_items )
131 {
132 if( crossProbingSettings.zoom_to_fit )
133 {
134 BOX2I bbox = symbol->GetBoundingBox();
135
136 m_toolMgr->GetTool<SCH_SELECTION_TOOL>()->ZoomFitCrossProbeBBox( bbox );
137 }
138
139 if( pin )
141 else
142 m_frame->FocusOnItem( symbol );
143 }
144 }
145
146 /* Print diag */
147 wxString msg;
148 wxString displayRef;
149
150 if( aReference )
151 displayRef = *aReference;
152 else if( aPath )
153 displayRef = *aPath;
154
155 if( symbol )
156 {
157 if( aSearchType == HIGHLIGHT_PIN )
158 {
159 if( foundItem )
160 msg.Printf( _( "%s pin %s found" ), displayRef, aSearchText );
161 else
162 msg.Printf( _( "%s found but pin %s not found" ), displayRef, aSearchText );
163 }
164 else
165 {
166 msg.Printf( _( "%s found" ), displayRef );
167 }
168 }
169 else
170 {
171 msg.Printf( _( "%s not found" ), displayRef );
172 }
173
174 m_frame->SetStatusText( msg );
176
177 return foundItem;
178}
179
180
181/* Execute a remote command sent via a socket on port KICAD_PCB_PORT_SERVICE_NUMBER
182 *
183 * Commands are:
184 *
185 * $PART: "reference" Put cursor on symbol.
186 * $PART: "reference" $REF: "ref" Put cursor on symbol reference.
187 * $PART: "reference" $VAL: "value" Put cursor on symbol value.
188 * $PART: "reference" $PAD: "pin name" Put cursor on the symbol pin.
189 * $NET: "netname" Highlight a specified net
190 * $CLEAR: "HIGHLIGHTED" Clear symbols highlight
191 *
192 * $CONFIG Show the Manage Symbol Libraries dialog
193 * $ERC Show the ERC dialog
194 */
195void SCH_EDIT_FRAME::ExecuteRemoteCommand( const char* cmdline )
196{
198 char line[1024];
199
200 strncpy( line, cmdline, sizeof( line ) - 1 );
201 line[ sizeof( line ) - 1 ] = '\0';
202
203 char* idcmd = strtok( line, " \n\r" );
204 char* text = strtok( nullptr, "\"\n\r" );
205
206 if( idcmd == nullptr )
207 return;
208
209 CROSS_PROBING_SETTINGS& crossProbingSettings = eeconfig()->m_CrossProbing;
210
211 if( strcmp( idcmd, "$CONFIG" ) == 0 )
212 {
214 return;
215 }
216 else if( strcmp( idcmd, "$ERC" ) == 0 )
217 {
219 return;
220 }
221 else if( strcmp( idcmd, "$NET:" ) == 0 )
222 {
223 if( !crossProbingSettings.auto_highlight )
224 return;
225
226 wxString netName = From_UTF8( text );
227
228 if( auto sg = Schematic().ConnectionGraph()->FindFirstSubgraphByName( netName ) )
229 m_highlightedConn = sg->GetDriverConnection()->Name();
230 else
231 m_highlightedConn = wxEmptyString;
232
235
236 SetStatusText( _( "Selected net:" ) + wxS( " " ) + UnescapeString( netName ) );
237 return;
238 }
239 else if( strcmp( idcmd, "$CLEAR:" ) == 0 )
240 {
241 // Cross-probing is now done through selection so we no longer need a clear command
242 return;
243 }
244
245 if( !crossProbingSettings.on_selection )
246 return;
247
248 if( text == nullptr )
249 return;
250
251 if( strcmp( idcmd, "$PART:" ) != 0 )
252 return;
253
254 wxString part_ref = From_UTF8( text );
255
256 /* look for a complement */
257 idcmd = strtok( nullptr, " \n\r" );
258
259 if( idcmd == nullptr ) // Highlight symbol only (from CvPcb or Pcbnew)
260 {
261 // Highlight symbol part_ref, or clear Highlight, if part_ref is not existing
262 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
263 return;
264 }
265
266 text = strtok( nullptr, "\"\n\r" );
267
268 if( text == nullptr )
269 return;
270
271 wxString msg = From_UTF8( text );
272
273 if( strcmp( idcmd, "$REF:" ) == 0 )
274 {
275 // Highlighting the reference itself isn't actually that useful, and it's harder to
276 // see. Highlight the parent and display the message.
277 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
278 }
279 else if( strcmp( idcmd, "$VAL:" ) == 0 )
280 {
281 // Highlighting the value itself isn't actually that useful, and it's harder to see.
282 // Highlight the parent and display the message.
283 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, msg );
284 }
285 else if( strcmp( idcmd, "$PAD:" ) == 0 )
286 {
287 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_PIN, msg );
288 }
289 else
290 {
291 editor->FindSymbolAndItem( nullptr, &part_ref, true, HIGHLIGHT_SYMBOL, wxEmptyString );
292 }
293}
294
295
296void SCH_EDIT_FRAME::SendSelectItemsToPcb( const std::vector<EDA_ITEM*>& aItems, bool aForce )
297{
298 std::vector<wxString> parts;
299
300 for( EDA_ITEM* item : aItems )
301 {
302 switch( item->Type() )
303 {
304 case SCH_SYMBOL_T:
305 {
306 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
307 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
308
309 parts.push_back( wxT( "F" ) + EscapeString( ref, CTX_IPC ) );
310 break;
311 }
312
313 case SCH_SHEET_T:
314 {
315 // For cross probing, we need the full path of the sheet, because
316 // we search by the footprint path prefix in the PCB editor
317 wxString full_path = GetCurrentSheet().PathAsString() + item->m_Uuid.AsString();
318
319 parts.push_back( wxT( "S" ) + full_path );
320 break;
321 }
322
323 case SCH_PIN_T:
324 {
325 SCH_PIN* pin = static_cast<SCH_PIN*>( item );
326 SYMBOL* symbol = pin->GetParentSymbol();
327 wxString ref = symbol->GetRef( &GetCurrentSheet(), false );
328
329 parts.push_back( wxT( "P" ) + EscapeString( ref, CTX_IPC ) + wxT( "/" )
330 + EscapeString( pin->GetShownNumber(), CTX_IPC ) );
331 break;
332 }
333
334 default:
335 break;
336 }
337 }
338
339 if( parts.empty() )
340 return;
341
342 std::string command = "$SELECT: 0,";
343
344 for( wxString part : parts )
345 {
346 command += part;
347 command += ",";
348 }
349
350 command.pop_back();
351
352 if( Kiface().IsSingle() )
353 {
354 SendCommand( MSG_TO_PCB, command );
355 }
356 else
357 {
358 // Typically ExpressMail is going to be s-expression packets, but since
359 // we have existing interpreter of the selection packet on the other
360 // side in place, we use that here.
362 command, this );
363 }
364}
365
366
367void SCH_EDIT_FRAME::SendCrossProbeNetName( const wxString& aNetName )
368{
369 // The command is a keyword followed by a quoted string.
370
371 std::string packet = StrPrintf( "$NET: \"%s\"", TO_UTF8( aNetName ) );
372
373 if( !packet.empty() )
374 {
375 if( Kiface().IsSingle() )
376 {
377 SendCommand( MSG_TO_PCB, packet );
378 }
379 else
380 {
381 // Typically ExpressMail is going to be s-expression packets, but since
382 // we have existing interpreter of the cross probe packet on the other
383 // side in place, we use that here.
385 }
386 }
387}
388
389
391{
392 if( !aConnection )
393 {
395 return;
396 }
397
398 if( aConnection->IsNet() )
399 {
400 SendCrossProbeNetName( aConnection->Name() );
401 return;
402 }
403
404 if( aConnection->Members().empty() )
405 return;
406
407 auto all_members = aConnection->AllMembers();
408
409 wxString nets = all_members[0]->Name();
410
411 if( all_members.size() == 1 )
412 {
413 SendCrossProbeNetName( nets );
414 return;
415 }
416
417 // TODO: This could be replaced by just sending the bus name once we have bus contents
418 // included as part of the netlist sent from Eeschema to Pcbnew (and thus Pcbnew can
419 // natively keep track of bus membership)
420
421 for( size_t i = 1; i < all_members.size(); i++ )
422 nets << "," << all_members[i]->Name();
423
424 std::string packet = StrPrintf( "$NETS: \"%s\"", TO_UTF8( nets ) );
425
426 if( !packet.empty() )
427 {
428 if( Kiface().IsSingle() )
429 SendCommand( MSG_TO_PCB, packet );
430 else
431 {
432 // Typically ExpressMail is going to be s-expression packets, but since
433 // we have existing interpreter of the cross probe packet on the other
434 // side in place, we use that here.
436 }
437 }
438}
439
440
442{
443 std::string packet = "$CLEAR\n";
444
445 if( Kiface().IsSingle() )
446 {
447 SendCommand( MSG_TO_PCB, packet );
448 }
449 else
450 {
451 // Typically ExpressMail is going to be s-expression packets, but since
452 // we have existing interpreter of the cross probe packet on the other
453 // side in place, we use that here.
455 }
456}
457
458
460 const SCH_SHEET_LIST& aSchematicSheetList, const SCH_SHEET_PATH& aSheetPath,
461 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
462 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
463 bool aRecursive = false )
464{
465 if( aRecursive )
466 {
467 // Iterate over children
468 for( const SCH_SHEET_PATH& candidate : aSchematicSheetList )
469 {
470 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
471 continue;
472
473 findSymbolsAndPins( aSchematicSheetList, candidate, aSyncSymMap, aSyncPinMap,
474 aRecursive );
475 }
476 }
477
478 SCH_REFERENCE_LIST references;
479
480 aSheetPath.GetSymbols( references, false, true );
481
482 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
483 {
484 SCH_REFERENCE& schRef = references[ii];
485
486 if( schRef.IsSplitNeeded() )
487 schRef.Split();
488
489 SCH_SYMBOL* symbol = schRef.GetSymbol();
490 wxString refNum = schRef.GetRefNumber();
491 wxString fullRef = schRef.GetRef() + refNum;
492
493 // Skip power symbols
494 if( fullRef.StartsWith( wxS( "#" ) ) )
495 continue;
496
497 // Unannotated symbols are not supported
498 if( refNum.compare( wxS( "?" ) ) == 0 )
499 continue;
500
501 // Look for whole footprint
502 auto symMatchIt = aSyncSymMap.find( fullRef );
503
504 if( symMatchIt != aSyncSymMap.end() )
505 {
506 symMatchIt->second.emplace_back( schRef );
507
508 // Whole footprint was selected, no need to select pins
509 continue;
510 }
511
512 // Look for pins
513 auto symPinMatchIt = aSyncPinMap.find( fullRef );
514
515 if( symPinMatchIt != aSyncPinMap.end() )
516 {
517 std::unordered_map<wxString, SCH_PIN*>& pinMap = symPinMatchIt->second;
518 std::vector<SCH_PIN*> pinsOnSheet = symbol->GetPins( &aSheetPath );
519
520 for( SCH_PIN* pin : pinsOnSheet )
521 {
522 int pinUnit = pin->GetLibPin()->GetUnit();
523
524 if( pinUnit > 0 && pinUnit != schRef.GetUnit() )
525 continue;
526
527 auto pinIt = pinMap.find( pin->GetNumber() );
528
529 if( pinIt != pinMap.end() )
530 pinIt->second = pin;
531 }
532 }
533 }
534
535 return false;
536}
537
538
540 const SCH_SHEET_LIST& aSchematicSheetList, const SCH_SHEET_PATH& aSheetPath,
541 std::unordered_map<wxString, std::vector<SCH_REFERENCE>>& aSyncSymMap,
542 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>>& aSyncPinMap,
543 std::unordered_map<SCH_SHEET_PATH, bool>& aCache )
544{
545 auto cacheIt = aCache.find( aSheetPath );
546
547 if( cacheIt != aCache.end() )
548 return cacheIt->second;
549
550 // Iterate over children
551 for( const SCH_SHEET_PATH& candidate : aSchematicSheetList )
552 {
553 if( candidate == aSheetPath || !candidate.IsContainedWithin( aSheetPath ) )
554 continue;
555
556 bool childRet = sheetContainsOnlyWantedItems( aSchematicSheetList, candidate, aSyncSymMap,
557 aSyncPinMap, aCache );
558
559 if( !childRet )
560 {
561 aCache.emplace( aSheetPath, false );
562 return false;
563 }
564 }
565
566 SCH_REFERENCE_LIST references;
567 aSheetPath.GetSymbols( references, false, true );
568
569 if( references.GetCount() == 0 ) // Empty sheet, obviously do not contain wanted items
570 {
571 aCache.emplace( aSheetPath, false );
572 return false;
573 }
574
575 for( unsigned ii = 0; ii < references.GetCount(); ii++ )
576 {
577 SCH_REFERENCE& schRef = references[ii];
578
579 if( schRef.IsSplitNeeded() )
580 schRef.Split();
581
582 wxString refNum = schRef.GetRefNumber();
583 wxString fullRef = schRef.GetRef() + refNum;
584
585 // Skip power symbols
586 if( fullRef.StartsWith( wxS( "#" ) ) )
587 continue;
588
589 // Unannotated symbols are not supported
590 if( refNum.compare( wxS( "?" ) ) == 0 )
591 continue;
592
593 if( aSyncSymMap.find( fullRef ) == aSyncSymMap.end() )
594 {
595 aCache.emplace( aSheetPath, false );
596 return false; // Some symbol is not wanted.
597 }
598
599 if( aSyncPinMap.find( fullRef ) != aSyncPinMap.end() )
600 {
601 aCache.emplace( aSheetPath, false );
602 return false; // Looking for specific pins, so can't be mapped
603 }
604 }
605
606 aCache.emplace( aSheetPath, true );
607 return true;
608}
609
610
611std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>>
612findItemsFromSyncSelection( const SCHEMATIC& aSchematic, const std::string aSyncStr,
613 bool aFocusOnFirst )
614{
615 wxArrayString syncArray = wxStringTokenize( aSyncStr, wxS( "," ) );
616
617 std::unordered_map<wxString, std::vector<SCH_REFERENCE>> syncSymMap;
618 std::unordered_map<wxString, std::unordered_map<wxString, SCH_PIN*>> syncPinMap;
619 std::unordered_map<SCH_SHEET_PATH, double> symScores;
620 std::unordered_map<SCH_SHEET_PATH, bool> fullyWantedCache;
621
622 std::optional<wxString> focusSymbol;
623 std::optional<std::pair<wxString, wxString>> focusPin;
624 std::unordered_map<SCH_SHEET_PATH, std::vector<SCH_ITEM*>> focusItemResults;
625
626 const SCH_SHEET_LIST allSheetsList = aSchematic.Hierarchy();
627
628 // In orderedSheets, the current sheet comes first.
629 std::vector<SCH_SHEET_PATH> orderedSheets;
630 orderedSheets.reserve( allSheetsList.size() );
631 orderedSheets.push_back( aSchematic.CurrentSheet() );
632
633 for( const SCH_SHEET_PATH& sheetPath : allSheetsList )
634 {
635 if( sheetPath != aSchematic.CurrentSheet() )
636 orderedSheets.push_back( sheetPath );
637 }
638
639 // Init sync maps from the sync string
640 for( size_t i = 0; i < syncArray.size(); i++ )
641 {
642 wxString syncEntry = syncArray[i];
643
644 if( syncEntry.empty() )
645 continue;
646
647 wxString syncData = syncEntry.substr( 1 );
648
649 switch( syncEntry.GetChar( 0 ).GetValue() )
650 {
651 case 'F': // Select by footprint: F<Reference>
652 {
653 wxString symRef = UnescapeString( syncData );
654
655 if( aFocusOnFirst && ( i == 0 ) )
656 focusSymbol = symRef;
657
658 syncSymMap[symRef] = std::vector<SCH_REFERENCE>();
659 break;
660 }
661
662 case 'P': // Select by pad: P<Footprint reference>/<Pad number>
663 {
664 wxString symRef = UnescapeString( syncData.BeforeFirst( '/' ) );
665 wxString padNum = UnescapeString( syncData.AfterFirst( '/' ) );
666
667 if( aFocusOnFirst && ( i == 0 ) )
668 focusPin = std::make_pair( symRef, padNum );
669
670 syncPinMap[symRef][padNum] = nullptr;
671 break;
672 }
673
674 default:
675 break;
676 }
677 }
678
679 // Lambda definitions
680 auto flattenSyncMaps =
681 [&syncSymMap, &syncPinMap]() -> std::vector<SCH_ITEM*>
682 {
683 std::vector<SCH_ITEM*> allVec;
684
685 for( const auto& [symRef, symbols] : syncSymMap )
686 {
687 for( const SCH_REFERENCE& ref : symbols )
688 allVec.push_back( ref.GetSymbol() );
689 }
690
691 for( const auto& [symRef, pinMap] : syncPinMap )
692 {
693 for( const auto& [padNum, pin] : pinMap )
694 {
695 if( pin )
696 allVec.push_back( pin );
697 }
698 }
699
700 return allVec;
701 };
702
703 auto clearSyncMaps =
704 [&syncSymMap, &syncPinMap]()
705 {
706 for( auto& [symRef, symbols] : syncSymMap )
707 symbols.clear();
708
709 for( auto& [reference, pins] : syncPinMap )
710 {
711 for( auto& [number, pin] : pins )
712 pin = nullptr;
713 }
714 };
715
716 auto syncMapsValuesEmpty =
717 [&syncSymMap, &syncPinMap]() -> bool
718 {
719 for( const auto& [symRef, symbols] : syncSymMap )
720 {
721 if( symbols.size() > 0 )
722 return false;
723 }
724
725 for( const auto& [symRef, pins] : syncPinMap )
726 {
727 for( const auto& [padNum, pin] : pins )
728 {
729 if( pin )
730 return false;
731 }
732 }
733
734 return true;
735 };
736
737 auto checkFocusItems =
738 [&]( const SCH_SHEET_PATH& aSheet )
739 {
740 if( focusSymbol )
741 {
742 auto findIt = syncSymMap.find( *focusSymbol );
743
744 if( findIt != syncSymMap.end() )
745 {
746 if( findIt->second.size() > 0 )
747 focusItemResults[aSheet].push_back( findIt->second.front().GetSymbol() );
748 }
749 }
750 else if( focusPin )
751 {
752 auto findIt = syncPinMap.find( focusPin->first );
753
754 if( findIt != syncPinMap.end() )
755 {
756 if( findIt->second[focusPin->second] )
757 focusItemResults[aSheet].push_back( findIt->second[focusPin->second] );
758 }
759 }
760 };
761
762 auto makeRetForSheet =
763 [&]( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aFocusItem )
764 {
765 clearSyncMaps();
766
767 // Fill sync maps
768 findSymbolsAndPins( allSheetsList, aSheet, syncSymMap, syncPinMap );
769 std::vector<SCH_ITEM*> itemsVector = flattenSyncMaps();
770
771 // Add fully wanted sheets to vector
772 for( SCH_ITEM* item : aSheet.LastScreen()->Items().OfType( SCH_SHEET_T ) )
773 {
774 KIID_PATH kiidPath = aSheet.Path();
775 kiidPath.push_back( item->m_Uuid );
776
777 std::optional<SCH_SHEET_PATH> subsheetPath =
778 allSheetsList.GetSheetPathByKIIDPath( kiidPath );
779
780 if( !subsheetPath )
781 continue;
782
783 if( sheetContainsOnlyWantedItems( allSheetsList, *subsheetPath, syncSymMap,
784 syncPinMap, fullyWantedCache ) )
785 {
786 itemsVector.push_back( item );
787 }
788 }
789
790 return std::make_tuple( aSheet, aFocusItem, itemsVector );
791 };
792
793 if( aFocusOnFirst )
794 {
795 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
796 {
797 clearSyncMaps();
798
799 findSymbolsAndPins( allSheetsList, sheetPath, syncSymMap, syncPinMap );
800
801 checkFocusItems( sheetPath );
802 }
803
804 if( focusItemResults.size() > 0 )
805 {
806 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
807 {
808 const std::vector<SCH_ITEM*>& items = focusItemResults[sheetPath];
809
810 if( !items.empty() )
811 return makeRetForSheet( sheetPath, items.front() );
812 }
813 }
814 }
815 else
816 {
817 for( const SCH_SHEET_PATH& sheetPath : orderedSheets )
818 {
819 clearSyncMaps();
820
821 findSymbolsAndPins( allSheetsList, sheetPath, syncSymMap, syncPinMap );
822
823 if( !syncMapsValuesEmpty() )
824 {
825 // Something found on sheet
826 return makeRetForSheet( sheetPath, nullptr );
827 }
828 }
829 }
830
831 return std::nullopt;
832}
833
834
836{
837 std::string& payload = mail.GetPayload();
838
839 switch( mail.Command() )
840 {
842 {
843 std::stringstream ss( payload );
844 std::string file;
846
847 wxCHECK_RET( symLibTbl, "Could not load symbol lib table." );
848
849 while( std::getline( ss, file, '\n' ) )
850 {
851 if( file.empty() )
852 continue;
853
854 wxFileName fn( file );
856 SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
857
858 if( type == SCH_IO_MGR::SCH_FILE_UNKNOWN )
859 {
860 wxLogTrace( "KIWAY", "Unknown file type: %s", fn.GetFullPath() );
861 continue;
862 }
863
864 pi.reset( SCH_IO_MGR::FindPlugin( type ) );
865
866 if( !symLibTbl->HasLibrary( fn.GetName() ) )
867 {
868 symLibTbl->InsertRow( new SYMBOL_LIB_TABLE_ROW( fn.GetName(), fn.GetFullPath(),
869 SCH_IO_MGR::ShowType( type ) ) );
870 wxString tblName = Prj().SymbolLibTableName();
871
872 try
873 {
874 symLibTbl->Save( tblName );
875 }
876 catch( const IO_ERROR& ioe )
877 {
878 wxLogError( _( "Error saving project-specific library table:\n\n%s" ), ioe.What() );
879 }
880 }
881 }
882
886
887 break;
888 }
889
890 case MAIL_CROSS_PROBE:
891 ExecuteRemoteCommand( payload.c_str() );
892 break;
893
894 case MAIL_SELECTION:
895 if( !eeconfig()->m_CrossProbing.on_selection )
896 break;
897
899
901 {
902 // $SELECT: 0,<spec1>,<spec2>,<spec3>
903 // Try to select specified items.
904
905 // $SELECT: 1,<spec1>,<spec2>,<spec3>
906 // Select and focus on <spec1> item, select other specified items that are on the
907 // same sheet.
908
909 std::string prefix = "$SELECT: ";
910
911 std::string paramStr = payload.substr( prefix.size() );
912
913 // Empty/broken command: we need at least 2 chars for sync string.
914 if( paramStr.size() < 2 )
915 break;
916
917 std::string syncStr = paramStr.substr( 2 );
918
919 bool focusOnFirst = ( paramStr[0] == '1' );
920
921 std::optional<std::tuple<SCH_SHEET_PATH, SCH_ITEM*, std::vector<SCH_ITEM*>>> findRet =
922 findItemsFromSyncSelection( Schematic(), syncStr, focusOnFirst );
923
924 if( findRet )
925 {
926 auto& [sheetPath, focusItem, items] = *findRet;
927
928 m_syncingPcbToSchSelection = true; // recursion guard
929
930 GetToolManager()->GetTool<SCH_SELECTION_TOOL>()->SyncSelection( sheetPath, focusItem,
931 items );
932
934 }
935
936 break;
937 }
938
940 {
941 if( !payload.empty() )
942 {
943 wxString annotationMessage( payload );
944
945 // Ensure schematic is OK for netlist creation (especially that it is fully annotated):
946 if( !ReadyToNetlist( annotationMessage ) )
947 return;
948 }
949
950 if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
952
953 NETLIST_EXPORTER_KICAD exporter( &Schematic() );
954 STRING_FORMATTER formatter;
955
956 exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
957
958 payload = formatter.GetString();
959 break;
960 }
961
963 {
964 KIID uuid( payload );
966
967 if( SCH_ITEM* item = m_schematic->GetItem( uuid, &path ) )
968 {
969 if( item->Type() == SCH_SHEET_T )
970 payload = static_cast<SCH_SHEET*>( item )->GetShownName( false );
971 else if( item->Type() == SCH_SYMBOL_T )
972 payload = static_cast<SCH_SYMBOL*>( item )->GetRef( &path, true );
973 else
974 payload = item->GetFriendlyName();
975 }
976
977 break;
978 }
979
981 try
982 {
984 controlTool->AssignFootprints( payload );
985 }
986 catch( const IO_ERROR& )
987 {
988 }
989 break;
990
991 case MAIL_SCH_REFRESH:
992 {
994
996 GetCanvas()->Refresh();
997 break;
998 }
999
1000 case MAIL_IMPORT_FILE:
1001 {
1002 // Extract file format type and path (plugin type, path and properties keys, values
1003 // separated with \n)
1004 std::stringstream ss( payload );
1005 char delim = '\n';
1006
1007 std::string formatStr;
1008 wxCHECK( std::getline( ss, formatStr, delim ), /* void */ );
1009
1010 std::string fnameStr;
1011 wxCHECK( std::getline( ss, fnameStr, delim ), /* void */ );
1012
1013 int importFormat;
1014
1015 try
1016 {
1017 importFormat = std::stoi( formatStr );
1018 }
1019 catch( std::invalid_argument& )
1020 {
1021 wxFAIL;
1022 importFormat = -1;
1023 }
1024
1025 std::map<std::string, UTF8> props;
1026
1027 do
1028 {
1029 std::string key, value;
1030
1031 if( !std::getline( ss, key, delim ) )
1032 break;
1033
1034 std::getline( ss, value, delim ); // We may want an empty string as value
1035
1036 props.emplace( key, value );
1037
1038 } while( true );
1039
1040 if( importFormat >= 0 )
1041 importFile( fnameStr, importFormat, props.empty() ? nullptr : &props );
1042
1043 break;
1044 }
1045
1046 case MAIL_SCH_SAVE:
1047 if( SaveProject() )
1048 payload = "success";
1049
1050 break;
1051
1052 case MAIL_SCH_UPDATE:
1054 break;
1055
1056 case MAIL_RELOAD_LIB:
1058 SyncView();
1059 break;
1060
1061 default:;
1062
1063 }
1064}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION showSymbolLibTable
Definition: actions.h:273
static TOOL_ACTION updateSchematicFromPcb
Definition: actions.h:259
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:194
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:96
const KIID m_Uuid
Definition: eda_item.h:498
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.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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:1549
Definition: kiid.h:49
wxString AsString() const
Definition: kiid.cpp:246
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
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
Generate the KiCad netlist format supported by Pcbnew.
void Format(OUTPUTFORMATTER *aOutputFormatter, int aCtl)
Output this s-expression netlist into aOutputFormatter.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual const wxString SymbolLibTableName() const
Return the path and file name of this projects symbol library table.
Definition: project.cpp:170
Holds all the data relating to one schematic.
Definition: schematic.h:69
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:208
SCH_ITEM * GetItem(const KIID &aID, SCH_SHEET_PATH *aPathOut=nullptr) const
Definition: schematic.h:112
SCH_SHEET_PATH & CurrentSheet() const
Definition: schematic.h:148
static TOOL_ACTION runERC
Inspection and Editing.
Definition: sch_actions.h:144
static TOOL_ACTION changeSheet
Definition: sch_actions.h:216
static TOOL_ACTION updateNetHighlighting
Definition: sch_actions.h:295
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsNet() const
const std::vector< std::shared_ptr< SCH_CONNECTION > > AllMembers() const
wxString Name(bool aIgnoreSheet=false) const
const std::vector< std::shared_ptr< SCH_CONNECTION > > & Members() const
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
Handle actions specific to the schematic editor.
void AssignFootprints(const std::string &aChangedSetOfReferences)
SCH_ITEM * FindSymbolAndItem(const wxString *aPath, const wxString *aReference, bool aSearchHierarchy, SCH_SEARCH_T aSearchType, const wxString &aSearchText)
Find a symbol in the schematic and an item in this symbol and select it.
bool ReadyToNetlist(const wxString &aAnnotateMessage)
Check if we are ready to write a netlist file for the current schematic.
bool m_syncingPcbToSchSelection
void SendSelectItemsToPcb(const std::vector< EDA_ITEM * > &aItems, bool aForce)
Send items to board editor for selection.
void SendCrossProbeClearHighlight()
Tell Pcbnew to clear the existing highlighted net, if one exists.
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)
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 RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
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(EDA_ITEM *aItem) override
Focus on a particular canvas item.
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.
Definition: sch_io_mgr.cpp:83
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.
Definition: sch_io_mgr.cpp:140
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:236
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()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:112
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:75
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
Definition: sch_symbol.cpp:611
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition: sch_symbol.cpp:813
Implement an OUTPUTFORMATTER to a memory buffer.
Definition: richio.h:449
const std::string & GetString()
Definition: richio.h:472
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
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
Definition: tools_holder.h:171
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
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:150
#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
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:597
#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
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:70
@ GLOBAL_CLEANUP
SCH_SEARCH_T
Schematic search type used by the socket link with Pcbnew.
@ HIGHLIGHT_SYMBOL
@ HIGHLIGHT_PIN
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:403
@ 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
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
@ SCH_SHEET_T
Definition: typeinfo.h:175
@ SCH_PIN_T
Definition: typeinfo.h:153