KiCad PCB EDA Suite
Loading...
Searching...
No Matches
conn_facade.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "conn_facade.h"
21#include "conn_netchain_input.h"
23#include "conn_text.h"
24#include <algorithm>
25#include <array>
26#include <iterator>
27#include <ranges>
28#include <span>
29#include <limits>
30#include <stdexcept>
31#include <utility>
32#include <schematic.h>
33#include <bus_alias.h>
34#include <sch_screen.h>
35#include <sch_sheet_path.h>
36#include <sch_sheet.h>
37#include <sch_line.h>
38#include <sch_bus_entry.h>
39#include <sch_label.h>
40#include <sch_pin.h>
41#include <sch_rule_area.h>
44#include <wx/filefn.h>
46#include <wx/thread.h>
48
49namespace SCH_CONNECTIVITY
50{
51namespace
52{
53std::optional<TEXT_EVAL_VCS::CONTEXT_PATH_SCOPE> sourceProjectContext( const SCHEMATIC& aSchematic )
54{
55 if( aSchematic.IsValid() )
56 {
57 if( const wxString path = aSchematic.Project().GetProjectPath(); !path.IsEmpty() )
58 return std::optional<TEXT_EVAL_VCS::CONTEXT_PATH_SCOPE>( std::in_place, path );
59 }
60
61 return std::nullopt;
62}
63
64struct INSTANCE_TEXT_CONTEXT
65{
66 KIID_PATH path;
67 SCREEN_ID screen = 0;
68 wxString page;
69 wxString humanPath;
70 wxString sheetName;
71 wxString filename;
72 std::vector<wxString> title;
73 wxString paper;
74 VECTOR2D pageSize;
75 bool portrait = false;
76 bool operator==( const INSTANCE_TEXT_CONTEXT& ) const = default;
77};
78
79struct VARIANT_TEXT_CONTEXT
80{
81 std::map<wxString, wxString> fields;
82 std::array<bool, 5> attributes{};
83 bool operator==( const VARIANT_TEXT_CONTEXT& ) const = default;
84};
85
86struct SHEET_TEXT_CONTEXT
87{
88 std::vector<std::tuple<FIELD_T, wxString, wxString>> fields;
89 std::array<bool, 5> attributes{};
90 std::map<KIID_PATH, std::map<wxString, VARIANT_TEXT_CONTEXT>> variants;
91 bool operator==( const SHEET_TEXT_CONTEXT& ) const = default;
92};
93
94struct MODEL_TEXT_CONTEXT
95{
96 wxString projectFile;
97 wxString projectName;
98 wxString rootFile;
99 wxString workingDirectory;
100 wxString drawingLayout;
101 bool allowEmptyLayout = false;
102 wxString vcsContext;
103 bool vcsContextIsFile = false;
104 wxString variant;
105 wxString variantDescription;
106 int sheetCount = 0;
107 std::map<wxString, wxString> variables;
108 std::vector<wxString> templateFields;
109 std::vector<INSTANCE_TEXT_CONTEXT> instances;
110 std::map<KIID_PATH, SHEET_TEXT_CONTEXT> sheets;
111 bool operator==( const MODEL_TEXT_CONTEXT& ) const = default;
112};
113
114std::optional<MODEL_TEXT_CONTEXT> CaptureTextContext( SCHEMATIC& aSchematic, const SCH_SHEET_LIST& aPaths )
115{
116 MODEL_TEXT_CONTEXT result;
117
118 if( !aSchematic.IsValid() )
119 return std::nullopt;
120
121 PROJECT& project = aSchematic.Project();
122 result.projectFile = project.GetProjectFullName();
123 result.projectName = project.GetProjectName();
124 result.rootFile = aSchematic.GetFileName();
125 result.workingDirectory = wxGetCwd();
126
127 if( project.GetProjectPath().empty() )
128 {
130 result.vcsContextIsFile = TEXT_EVAL_VCS::GetContextIsFile();
131 }
132
133 DS_DATA_MODEL& layout = DS_DATA_MODEL::GetTheInstance();
134 layout.SaveInString( &result.drawingLayout );
135 result.allowEmptyLayout = layout.VoidListAllowed();
136 result.variant = aSchematic.GetCurrentVariant();
137 result.variantDescription = aSchematic.GetVariantDescription( result.variant );
138 result.sheetCount = aSchematic.Root().CountSheets();
139 result.variables = project.GetTextVars();
140
141 for( const auto& field : project.GetProjectFile().m_TemplateFieldNames.GetResolvedTemplateFieldNames() )
142 result.templateFields.push_back( field.m_Name );
143
144 for( const SCH_SHEET_PATH& path : aPaths )
145 {
146 SCH_SCREEN* screen = path.LastScreen();
147
148 if( !screen )
149 continue;
150
151 const TITLE_BLOCK& title = screen->GetTitleBlock();
152 INSTANCE_TEXT_CONTEXT instance{ path.Path(), screen->ConnectivityId(),
153 path.GetPageNumber(), path.PathHumanReadable(), path.Last()->GetName(),
154 screen->GetFileName(),
155 { title.GetTitle(), title.GetDate(), title.GetRevision(), title.GetCompany() },
157 screen->GetPageSettings().GetSizeMils(),
158 screen->GetPageSettings().IsPortrait() };
159
160 for( int comment = 0; comment < 9; ++comment )
161 instance.title.push_back( title.GetComment( comment ) );
162
163 result.instances.push_back( std::move( instance ) );
164 KIID_PATH sheetPath;
165
166 for( size_t depth = 0; depth < path.size(); ++depth )
167 {
168 const SCH_SHEET* sheet = path.at( depth );
169 sheetPath.push_back( sheet->m_Uuid );
170
171 if( result.sheets.contains( sheetPath ) )
172 continue;
173
174 SHEET_TEXT_CONTEXT source;
175 source.attributes = { sheet->GetDNP(), sheet->GetExcludedFromSim(), sheet->GetExcludedFromBOM(),
177
178 for( const SCH_FIELD& field : sheet->GetFields() )
179 source.fields.emplace_back( field.GetId(), field.GetName( false ), field.GetText() );
180
181 for( const SCH_SHEET_INSTANCE& sheetInstance : sheet->GetInstances() )
182 {
183 auto& variants = source.variants[sheetInstance.m_Path];
184
185 for( const auto& [name, variant] : sheetInstance.m_Variants )
186 {
187 variants.emplace( name, VARIANT_TEXT_CONTEXT{
188 variant.m_Fields,
189 { variant.m_DNP, variant.m_ExcludedFromSim, variant.m_ExcludedFromBOM,
190 variant.m_ExcludedFromBoard, variant.m_ExcludedFromPosFiles } } );
191 }
192 }
193
194 result.sheets.emplace( sheetPath, std::move( source ) );
195 }
196 }
197
198 std::ranges::sort( result.instances, {}, &INSTANCE_TEXT_CONTEXT::path );
199 return result;
200}
201} // namespace
202
204{
206 {
207 std::shared_ptr<const COMPONENT_CONTENT> content;
208 std::map<INST_ID, std::vector<KIID>> instances;
209 };
210
212 {
213 std::vector<TEXT_CHECK_FACT> items;
214 std::optional<std::vector<TEXT_CHECK_FACT>> drawingSheet;
215 };
216
218 uint64_t resetGeneration = 0;
219 uint64_t dispatchGeneration = 0;
220 uint64_t nextListener = 0;
221 std::map<uint64_t, std::function<void( const CHANGE_SET& )>> listeners;
222 uint64_t textEpoch = 0;
223 std::optional<MODEL_TEXT_CONTEXT> textContext;
224 bool publicationApplied = false;
225 std::optional<std::map<KIID_PATH, TEXT_CHECKS>> textChecks;
226 std::optional<std::map<KIID_PATH, std::vector<SIMULATION_MODEL_FACT>>> simulationModels;
227 std::map<INST_ID, std::weak_ptr<const SCH_SCREEN::CONNECTIVITY_SOURCE>> sources;
228 std::map<NODE_ID, std::shared_ptr<const NET_ITEMS>> netItems;
229 unsigned publicationHolds = 0;
230
232 {
234 throw std::logic_error( "ERC sources require applied connectivity outside input capture" );
235
236 auto paths = aSchematic.BuildSheetListSortedByPageNumbers();
237
238 for( const SCH_SHEET_PATH& path : paths )
239 {
240 if( !path.LastScreen() )
241 continue;
242
243 const auto instance = engine.Keys().FindInstance( path.PathRef() );
244
245 if( !instance || Screen( *instance ) != path.LastScreen() )
246 throw std::logic_error( "ERC sources require current connectivity" );
247 }
248
249 return paths;
250 }
251
253 {
254 decltype( netItems ) current;
255
256 for( const auto& [node, component] : engine.Published().Components() )
257 {
258 const auto old = netItems.find( node );
259
260 if( old != netItems.end() && old->second->content == component.content )
261 {
262 current.emplace( node, old->second );
263 continue;
264 }
265
266 auto membership = std::make_shared<NET_ITEMS>();
267 membership->content = component.content;
268
269 for( const ITEM_KEY& item : component.content->items )
270 membership->instances[item.inst].push_back( item.item );
271
272 for( const SLOT_KEY& slot : component.content->slots )
273 membership->instances.try_emplace( slot.bundleDriver.inst );
274
275 current.emplace( node, std::move( membership ) );
276 }
277
278 netItems.swap( current );
279 }
280
281 std::vector<INST_ID> LiveInstances() const
282 {
283 std::vector<INST_ID> live;
284 live.reserve( sources.size() );
285
286 for( const auto& [instance, source] : sources )
287 {
288 if( Screen( source ) )
289 live.push_back( instance );
290 }
291
292 return live;
293 }
294
295 bool AnyLive( NODE_ID aNode, std::span<const INST_ID> aLive ) const
296 {
297 const auto found = netItems.find( aNode );
298 return found != netItems.end() && std::any_of( found->second->instances.begin(),
299 found->second->instances.end(), [&]( const auto& entry )
300 {
301 return std::binary_search( aLive.begin(), aLive.end(), entry.first );
302 } );
303 }
304
305 std::optional<NODE_ID> BusNode( const wxString& aName ) const
306 {
307 const auto node = engine.Published().FindByName( aName );
308 return node && engine.Published().Components().at( *node ).content->kind == KIND::BUNDLE
309 ? node : std::nullopt;
310 }
311
312 std::optional<NET_GROUP> Group( NODE_ID aNode, std::span<const INST_ID> aLive,
313 const std::weak_ptr<const FACADE_STATE>& aState ) const
314 {
315 const auto component = engine.Published().Components().find( aNode );
316
317 if( component == engine.Published().Components().end() || component->second.name == INVALID_ID )
318 return std::nullopt;
319
320 std::vector<INST_ID> instances;
321
322 for( const auto& [instance, items] : netItems.at( aNode )->instances )
323 {
324 if( std::binary_search( aLive.begin(), aLive.end(), instance ) )
325 instances.push_back( instance );
326 }
327
328 if( instances.empty() )
329 return std::nullopt;
330
331 std::ranges::sort( instances, std::less<>{}, std::bind_front( &SESSION_KEYS::Instance, &engine.Keys() ) );
332 NET_GROUP result{ engine.Keys().Name( component->second.name ), {} };
333 result.instances.reserve( instances.size() );
334
335 for( INST_ID instance : instances )
336 result.instances.push_back( NET_VIEW( aState, aNode, instance ) );
337
338 return result;
339 }
340
341 std::vector<NET_GROUP> Groups( std::vector<NODE_ID> aNodes, std::span<const INST_ID> aLive,
342 const std::weak_ptr<const FACADE_STATE>& aState ) const
343 {
344 // Unnamed components have no name to sort by, and Group drops them anyway
345 std::erase_if( aNodes,
346 [&]( NODE_ID aNode )
347 {
348 return engine.Published().Components().at( aNode ).name == INVALID_ID;
349 } );
350 std::ranges::sort( aNodes, NAME_LESS{ &engine.Keys() },
351 [&]( NODE_ID aNode )
352 {
353 return engine.Published().Components().at( aNode ).name;
354 } );
355 std::vector<NET_GROUP> result;
356 result.reserve( aNodes.size() );
357
358 for( NODE_ID node : aNodes )
359 {
360 if( auto group = Group( node, aLive, aState ) )
361 result.push_back( std::move( *group ) );
362 }
363
364 return result;
365 }
366
367 const PUBLISHED_COMPONENT* Net( NODE_ID aNode, INST_ID aInstance ) const
368 {
369 wxASSERT( wxThread::IsMain() );
370 const auto found = netItems.find( aNode );
371
372 if( found == netItems.end() || !found->second->instances.contains( aInstance ) || !Screen( aInstance ) )
373 return nullptr;
374
375 return &engine.Published().Components().at( aNode );
376 }
377
378 wxString Name( const PUBLISHED_COMPONENT& aComponent, bool aIgnoreSheet ) const
379 {
380 if( aComponent.name == INVALID_ID )
381 return {};
382
383 const wxString& name = engine.Keys().Name( aComponent.name );
384
385 if( aIgnoreSheet && aComponent.content->best )
386 {
387 const NAME_ID path = aComponent.content->best->path;
388
389 if( path != INVALID_ID )
390 return name.Mid( engine.Keys().Name( path ).length() );
391 }
392
393 return name;
394 }
395
396 KIID_PATH Sheet( const std::optional<ITEM_KEY>& aDriver ) const
397 {
398 return aDriver && Resolve( *aDriver ) ? engine.Keys().Instance( aDriver->inst ) : KIID_PATH();
399 }
400
402 const std::weak_ptr<const FACADE_STATE>& aState, const ITEM_RESULT* aRow = nullptr ) const
403 {
404 const auto& component = engine.Published().Components().at( aNode );
405 const auto& content = *component.content;
406
407 if( content.kind != KIND::BUNDLE || !content.best || !Resolve( content.best->source ) )
408 return {};
409
411 const auto* local = aRow && aRow->busSource ? &*aRow->busSource : nullptr;
412
413 if( local && !Resolve( local->source ) )
414 return {};
415
416 result.schema = local ? local->schema : content.best->schema;
417 result.tree = engine.FindBusTree( engine.Keys().Name( local ? aRow->localName : content.best->name ) );
418 wxASSERT( result.tree && content.best->schema->leaves.size() == content.members.size() );
419 std::span<const SLOT_KEY> slots = content.members;
420 std::vector<SLOT_KEY> localSlots;
421
422 if( local )
423 {
424 localSlots.resize( result.schema->leaves.size() );
425 // Keep local lookup aligned with BindBundle's matching and extra-slot identities
426 const BUS_ALIGNMENT alignment = Align( *result.schema, *content.best->schema );
427
428 for( const auto& [from, to] : alignment.matched )
429 localSlots[from] = content.members.at( to );
430
431 for( size_t from : alignment.unmappedLeft )
432 localSlots[from] = SLOT_KEY{ local->source, static_cast<uint32_t>( from ) };
433
434 slots = localSlots;
435 }
436
437 result.leaves.reserve( slots.size() );
438
439 for( const SLOT_KEY& slot : slots )
440 {
441 const NODE_ID leaf = engine.Published().SlotComponents().at( slot );
442 const auto& instances = netItems.at( leaf )->instances;
443 const INST_ID instance = instances.contains( aInstance ) ? aInstance : slot.bundleDriver.inst;
444 result.leaves.push_back( NET_VIEW( aState, leaf, instance ) );
445 }
446
447 return result;
448 }
449
450 SCH_SCREEN* Screen( INST_ID aInstance ) const
451 {
452 const auto found = sources.find( aInstance );
453
454 if( found == sources.end() )
455 return nullptr;
456
457 return Screen( found->second );
458 }
459
460 SCH_SCREEN* Screen( const std::weak_ptr<const SCH_SCREEN::CONNECTIVITY_SOURCE>& aSource ) const
461 {
462 const auto source = aSource.lock();
463
464 if( !source || !source->screen )
465 return nullptr;
466
467 SCH_SCREEN* screen = source->screen;
468 const auto& revisions = engine.Published().Auxiliary().ScreenRevisions();
469 const auto revision = revisions.find( screen->ConnectivityId() );
470
471 if( revision == revisions.end() )
472 return nullptr;
473
474 if( revision->second == screen->ConnectivityRevision() || publicationHolds > 0 )
475 return screen;
476
477 return RENDER_SCOPE::Active() ? screen : nullptr;
478 }
479
480 bool Current( const SCH_SCREEN& aScreen ) const
481 {
482 const auto& revisions = engine.Published().Auxiliary().ScreenRevisions();
483 const auto revision = revisions.find( aScreen.ConnectivityId() );
484 return revision != revisions.end() && revision->second == aScreen.ConnectivityRevision();
485 }
486
487 const ITEM_RESULT* Row( const ITEM_KEY& aItem ) const
488 {
489 wxASSERT( wxThread::IsMain() );
490
491 const SCH_SCREEN* screen = Screen( aItem.inst );
492
493 if( !screen )
494 return nullptr;
495
496 const auto& rows = engine.Published().Rows();
497 const auto row = rows.find( aItem );
498
499 if( row == rows.end() )
500 return nullptr;
501
502 // A canvas read of a changed screen must not revive the row of a deleted item
503 if( publicationHolds == 0 && !Current( *screen ) && !screen->GetConnectivityItem( aItem.item ) )
504 return nullptr;
505
506 return &row->second;
507 }
508
509 SCH_ITEM* Resolve( const ITEM_KEY& aItem ) const
510 {
511 SCH_SCREEN* screen = Screen( aItem.inst );
512 return screen ? screen->GetConnectivityItem( aItem.item ) : nullptr;
513 }
514};
515
516SUBSCRIPTION::SUBSCRIPTION( std::weak_ptr<FACADE_STATE> aState, uint64_t aId ) :
517 m_state( std::move( aState ) ), m_id( aId )
518{
519}
520
522
524 m_state( std::move( aOther.m_state ) ), m_id( std::exchange( aOther.m_id, 0 ) )
525{
526}
527
529{
530 if( this != &aOther )
531 {
532 Reset();
533 m_state = std::move( aOther.m_state );
534 m_id = std::exchange( aOther.m_id, 0 );
535 }
536
537 return *this;
538}
539
541{
542 wxASSERT( wxThread::IsMain() );
543
544 if( auto state = m_state.lock() )
545 state->listeners.erase( m_id );
546
547 m_state.reset();
548 m_id = 0;
549}
550
551FACADE::FACADE() : m_state( std::make_shared<FACADE_STATE>() ) {}
552
554{
555 Clear();
556 m_state->listeners.clear();
557}
558
559SUBSCRIPTION FACADE::Subscribe( std::function<void( const CHANGE_SET& )> aListener )
560{
561 wxASSERT( wxThread::IsMain() );
562
563 if( !aListener )
564 throw std::invalid_argument( "Connectivity listener is empty" );
565
566 if( m_state->nextListener == std::numeric_limits<uint64_t>::max() )
567 throw std::overflow_error( "Connectivity listener identities exhausted" );
568
569 const uint64_t id = ++m_state->nextListener;
570 m_state->listeners.emplace( id, std::move( aListener ) );
571 return SUBSCRIPTION( m_state, id );
572}
573
574void FACADE::Recalculate( SCHEMATIC& aSchematic, bool aRebuild,
575 const std::function<void( SCH_ITEM* )>& aChangedHandler )
576{
577 wxASSERT( wxThread::IsMain() );
578
579 if( !aSchematic.IsValid() )
580 throw std::invalid_argument( "Cannot apply connectivity without a schematic project" );
581
582 const auto state = m_state;
583 const auto handler = aChangedHandler;
584 const auto paths = aSchematic.BuildSheetListSortedByPageNumbers();
585
586 try
587 {
588 updateModel( aSchematic, paths, aRebuild );
589
590 NETCHAIN_INPUT chains;
591 chains.sheets.reserve( paths.size() );
592 struct SHEET_SOURCE
593 {
595 SCH_SCREEN* screen;
596 };
597 std::map<INST_ID, SHEET_SOURCE> sheets;
598
599 for( const SCH_SHEET_PATH& path : paths )
600 {
601 if( !path.LastScreen() )
602 continue;
603
604 const auto instance = Keys().FindInstance( path.PathRef() );
605
606 if( !instance )
607 throw std::logic_error( "Missing sheet instance while rebuilding netchains" );
608
609 SCH_SCREEN* screen = state->Screen( *instance );
610
611 if( !screen )
612 throw std::logic_error( "Stale screen while rebuilding netchains" );
613
614 chains.sheets.emplace_back( path, &chains.storage );
615 sheets.emplace( *instance, SHEET_SOURCE{ &chains.sheets.back(), screen } );
616 }
617
618 for( const auto& [key, row] : Published().Rows() )
619 {
620 const auto sheet = sheets.find( key.inst );
621 SCH_ITEM* item = sheet != sheets.end()
622 ? sheet->second.screen->GetConnectivityItem( key.item ) : nullptr;
623
624 if( !item )
625 throw std::logic_error( "Stale item while rebuilding netchains" );
626
627 if( row.kind != KIND::SIGNAL || ( item->Type() != SCH_PIN_T && item->Type() != SCH_LABEL_T ) )
628 continue;
629
630 NETCHAIN_INPUT::NET net{ row.name == INVALID_ID ? wxString() : Keys().Name( row.name ), {} };
631 net.key = SCH_NETCHAIN::MakeKey( net.name, row.component );
632 sheet->second.input->nets.emplace( item, std::move( net ) );
633 }
634
635 aSchematic.NetChains().Rebuild( chains );
636 }
637 catch( ... )
638 {
639 Clear();
640 throw;
641 }
642
643 std::map<SCREEN_ID, INST_ID> displayed;
644
645 for( const SCH_SHEET_PATH& path : paths )
646 {
647 if( const auto instance = Keys().FindInstance( path.PathRef() ) )
648 {
649 if( SCH_SCREEN* screen = state->Screen( *instance ) )
650 displayed[screen->ConnectivityId()] = *instance;
651 }
652 }
653
654 if( const auto current = Keys().FindInstance( aSchematic.CurrentSheet().PathRef() ) )
655 {
656 if( SCH_SCREEN* screen = state->Screen( *current ) )
657 displayed[screen->ConnectivityId()] = *current;
658 }
659
660 std::set<ITEM_KEY, KEY_LESS> changed( KEY_LESS{ Keys() } );
661 const auto& publishedChanges = Published().Changes().changedItems;
662 changed.insert( publishedChanges.begin(), publishedChanges.end() );
664 aSchematic.NetChains().ApplyNetChainNetclasses();
665
666 const auto applyEnds = []( auto* aItem, auto aDangling )
667 {
668 const bool differs = aItem->IsStartDangling() != bool( aDangling & 1 )
669 || aItem->IsEndDangling() != bool( aDangling & 2 );
670 aItem->SetDanglingState( aDangling & 1, aDangling & 2 );
671 return differs;
672 };
673
674 for( const auto& [key, island] : Published().Auxiliary().Islands() )
675 {
676 SCH_SCREEN* screen = state->Screen( key.inst );
677
678 if( !screen )
679 continue;
680
681 const auto instance = displayed.find( screen->ConnectivityId() );
682
683 if( instance == displayed.end() || instance->second != key.inst )
684 continue;
685
686 for( const auto& [id, dangling] : island.value.dangling )
687 {
688 SCH_ITEM* item = screen->GetConnectivityItem( id );
689 bool differs = false;
690
691 if( !item )
692 continue;
693
694 switch( item->Type() )
695 {
696 case SCH_LINE_T:
697 differs = applyEnds( static_cast<SCH_LINE*>( item ), dangling );
698 break;
701 differs = applyEnds( static_cast<SCH_BUS_ENTRY_BASE*>( item ), dangling );
702 break;
703 case SCH_LABEL_T:
705 case SCH_HIER_LABEL_T:
707 case SCH_SHEET_PIN_T:
708 {
709 auto* label = static_cast<SCH_LABEL_BASE*>( item );
710 differs = label->SCH_LABEL_BASE::IsDangling() != bool( dangling );
711 label->SetIsDangling( dangling );
712
713 if( label->Type() == SCH_DIRECTIVE_LABEL_T )
714 {
715 auto* directive = static_cast<SCH_DIRECTIVE_LABEL*>( label );
716 std::unordered_set<SCH_RULE_AREA*> areas;
717 const auto& auxiliary = Published().Auxiliary();
718 const auto attached = auxiliary.RuleAreasOf().find( { id, key.inst } );
719
720 if( attached != auxiliary.RuleAreasOf().end() )
721 {
722 for( const KIID& areaId : attached->second )
723 {
724 if( auto* live = dynamic_cast<SCH_RULE_AREA*>( screen->GetConnectivityItem( areaId ) ) )
725 areas.insert( live );
726 }
727 }
728
729 if( directive->GetConnectedRuleAreas() != areas )
730 {
731 directive->ClearConnectedRuleAreas();
732
733 for( SCH_RULE_AREA* area : areas )
734 directive->AddConnectedRuleArea( area );
735
736 differs = true;
737 }
738 }
739 break;
740 }
741 case SCH_PIN_T:
742 differs = static_cast<SCH_PIN*>( item )->SetIsDangling( dangling );
743 break;
744 default:
745 break;
746 }
747
748 if( differs )
749 changed.insert( { id, key.inst } );
750 }
751 }
752
753 for( const auto& [id, instance] : displayed )
754 {
755 SCH_SCREEN* screen = state->Screen( instance );
756
757 if( !screen )
758 continue;
759
760 for( SCH_ITEM* item : screen->Items() )
761 {
762 item->SetConnectivityDirty( false );
763 item->RunOnChildren( []( SCH_ITEM* child ) { child->SetConnectivityDirty( false ); },
765 }
766 }
767
768 state->publicationApplied = true;
769
770 const uint64_t generation = state->resetGeneration;
771 const uint64_t dispatch = ++state->dispatchGeneration;
772 std::vector<uint64_t> listeners;
773 CHANGE_SET notification;
774
775 if( !state->listeners.empty() )
776 {
777 notification = state->engine.Published().Changes();
778 notification.changedItems.assign( changed.begin(), changed.end() );
779 std::ranges::copy( state->listeners | std::views::keys, std::back_inserter( listeners ) );
780 }
781
782 // A callback that clears or recalculates makes the rest of this delivery obsolete
783 const auto superseded = [&]()
784 {
785 return state->resetGeneration != generation || state->dispatchGeneration != dispatch;
786 };
787
788 // The publication is already applied, so one failing callback must not starve the others
789 const auto deliver = []( const char* aKind, const auto& aCall )
790 {
791 try
792 {
793 aCall();
794 }
795 catch( const std::exception& error )
796 {
797 wxLogTrace( "KICAD_CONNECTIVITY", "Connectivity %s failed: %s", aKind, error.what() );
798 }
799 catch( ... )
800 {
801 wxLogTrace( "KICAD_CONNECTIVITY", "Connectivity %s failed with an unknown exception", aKind );
802 }
803 };
804
805 if( handler )
806 {
807 for( const ITEM_KEY& key : changed )
808 {
809 if( superseded() )
810 break;
811
812 if( SCH_ITEM* item = state->Resolve( key ) )
813 deliver( "change handler",
814 [&]()
815 {
816 handler( item );
817 } );
818 }
819 }
820
821 if( !notification.Empty() )
822 {
823 for( uint64_t id : listeners )
824 {
825 if( superseded() )
826 break;
827
828 const auto found = state->listeners.find( id );
829
830 if( found != state->listeners.end() )
831 {
832 const auto listener = found->second;
833 deliver( "listener",
834 [&]()
835 {
836 listener( notification );
837 } );
838 }
839 }
840 }
841}
842
843
844void FACADE::Update( SCHEMATIC& aSchematic, bool aRebuild )
845{
846 wxASSERT( wxThread::IsMain() );
847
848 try
849 {
850 updateModel( aSchematic, aSchematic.BuildSheetListSortedByPageNumbers(), aRebuild );
851 }
852 catch( ... )
853 {
854 Clear();
855 throw;
856 }
857}
858
859bool FACADE::UpdateShadow( SCHEMATIC& aSchematic, const SCH_SHEET_LIST& aPaths, bool aRebuild )
860{
861 try
862 {
863 updateModel( aSchematic, aPaths, aRebuild );
864 return true;
865 }
866 catch( const std::exception& error )
867 {
868 Clear();
869 wxLogTrace( "CONN_SHADOW", "Shadow connectivity failed: %s", error.what() );
870 }
871 catch( ... )
872 {
873 Clear();
874 wxLogTrace( "CONN_SHADOW", "Shadow connectivity failed with an unknown exception" );
875 }
876
877 return false;
878}
879
880
881void FACADE::ApplyNetclasses( NET_SETTINGS& aSettings ) const
882{
883 wxASSERT( wxThread::IsMain() );
884 std::map<wxString, std::set<wxString>> assignments;
885
886 for( const auto& [name, classes] : Published().Netclasses() )
887 {
888 auto& names = assignments[Keys().Name( name )];
889
890 for( NAME_ID netclass : *classes )
891 names.insert( Keys().Name( netclass ) );
892 }
893
894 std::vector<wxString> retired;
895
896 for( const auto& [name, classes] : aSettings.GetNetclassLabelAssignments() )
897 {
898 if( !assignments.contains( name ) )
899 retired.push_back( name );
900 }
901
902 for( const wxString& name : retired )
903 {
904 aSettings.ClearCacheForNet( name );
906 }
907
908 const auto& previous = aSettings.GetNetclassLabelAssignments();
909
910 for( const auto& [name, classes] : assignments )
911 {
912 const auto old = previous.find( name );
913
914 if( old == previous.end() || old->second != classes )
915 {
916 aSettings.SetNetclassLabelAssignment( name, classes );
917 aSettings.ClearCacheForNet( name );
918 }
919 }
920}
921
922
923void FACADE::updateModel( SCHEMATIC& aSchematic, const SCH_SHEET_LIST& aPaths, bool aRebuild )
924{
925 wxASSERT( wxThread::IsMain() );
926
927 TEXT_ENVIRONMENT environment;
928 INPUT_TEXT_SCOPE frame( environment );
929 auto context = CaptureTextContext( aSchematic, aPaths );
930 const bool changed = !context || m_state->textContext != context
931 || m_state->engine.ExternalSourcesChanged( aPaths, true );
932
933 if( changed && m_state->textEpoch == std::numeric_limits<uint64_t>::max() )
934 throw std::overflow_error( "Connectivity text epoch exhausted" );
935
936 BUS_ALIASES aliases;
937
938 for( const auto& alias : aSchematic.GetAllBusAliases() )
939 {
940 if( alias )
941 aliases.insert_or_assign( alias->GetName(), alias->Members() );
942 }
943
944 Update( aPaths, m_state->textEpoch + ( changed ? 1 : 0 ), aliases, aRebuild );
945 m_state->textContext = std::move( context );
946}
947
948void FACADE::Update( const SCH_SHEET_LIST& aPaths, uint64_t aTextEpoch, const BUS_ALIASES& aAliases, bool aRebuild )
949{
950 wxASSERT( wxThread::IsMain() );
951
952 m_state->textContext.reset();
953 m_state->publicationApplied = false;
954 m_state->textChecks.reset();
955 m_state->simulationModels.reset();
956
957 try
958 {
959 m_state->engine.Update( aPaths, aTextEpoch, aAliases, aRebuild );
960 decltype( m_state->sources ) sources;
961
962 for( const SCH_SHEET_PATH& path : aPaths )
963 {
964 if( SCH_SCREEN* screen = path.LastScreen() )
965 {
966 if( const auto instance = Keys().FindInstance( path.PathRef() ) )
967 sources.emplace( *instance, screen->ConnectivitySource() );
968 }
969 }
970
971 m_state->RefreshNetItems();
972 m_state->sources.swap( sources );
973 m_state->textEpoch = aTextEpoch;
974 }
975 catch( ... )
976 {
977 Clear();
978 throw;
979 }
980}
981
983{
984 m_state->publicationApplied = false;
985 m_state->textChecks.reset();
986 m_state->simulationModels.reset();
987 ++m_state->resetGeneration;
988 m_state->sources.clear();
989 m_state->netItems.clear();
990 m_state->engine.Clear();
991 m_state->textEpoch = 0;
992 m_state->textContext.reset();
993}
994
996{
997 wxASSERT( wxThread::IsMain() );
998 ++aFacade.m_state->publicationHolds;
999}
1000
1002{
1003 if( const auto state = m_state.lock() )
1004 --state->publicationHolds;
1005}
1006
1007const PUBLICATION& FACADE::Published() const { return m_state->engine.Published(); }
1008const SESSION_KEYS& FACADE::Keys() const { return m_state->engine.Keys(); }
1009const ENGINE& FACADE::Engine() const { return m_state->engine; }
1010
1011void FACADE::PrepareTextChecks( SCHEMATIC& aSchematic, bool aIncludeDrawingSheet )
1012{
1013 wxASSERT( wxThread::IsMain() );
1014 m_state->textChecks.reset();
1015 const auto paths = m_state->SourcePaths( aSchematic );
1016 const auto vcs = sourceProjectContext( aSchematic );
1017 std::optional<DS_DATA_MODEL> isolated;
1018 struct RESTORE_LAYOUT
1019 {
1020 DS_DATA_MODEL* previous = nullptr;
1021 ~RESTORE_LAYOUT()
1022 {
1023 if( previous )
1025 }
1026 } restoreLayout;
1027
1028 if( aIncludeDrawingSheet )
1029 {
1030 // Rendering replaces draw objects that the canvas may still reference
1032 wxString layout;
1033 original.SaveInString( &layout );
1034 isolated.emplace();
1035 restoreLayout.previous = &original;
1036 DS_DATA_MODEL::SetAltInstance( &*isolated );
1037 isolated->SetPageLayout( layout.utf8_str() );
1038 isolated->AllowVoidList( original.VoidListAllowed() );
1039 }
1040
1041 std::map<KIID_PATH, FACADE_STATE::TEXT_CHECKS> captured;
1042
1043 for( const SCH_SHEET_PATH& path : paths )
1044 {
1045 auto& checks = captured[path.PathRef()];
1046
1047 if( aIncludeDrawingSheet )
1048 checks.drawingSheet.emplace();
1049
1050 if( const SCH_SCREEN* screen = path.LastScreen() )
1051 {
1052 checks.items = ExtractTextChecks( *screen, path );
1053
1054 if( aIncludeDrawingSheet )
1055 checks.drawingSheet = ExtractDrawingSheetTextChecks( *screen, path );
1056 }
1057 }
1058
1059 m_state->textChecks = std::move( captured );
1060}
1061
1062std::vector<TEXT_CHECK_FACT> FACADE::TextChecks( const KIID_PATH& aPath, bool aDrawingSheet ) const
1063{
1064 wxASSERT( wxThread::IsMain() );
1065
1066 if( !m_state->textChecks )
1067 throw std::logic_error( "Text sources have not been prepared" );
1068
1069 const auto& captured = m_state->textChecks->at( aPath );
1070
1071 if( aDrawingSheet && !captured.drawingSheet )
1072 throw std::logic_error( "Drawing sheet text sources have not been prepared" );
1073
1074 return aDrawingSheet ? *captured.drawingSheet : captured.items;
1075}
1076
1078{
1079 wxASSERT( wxThread::IsMain() );
1080 m_state->simulationModels.reset();
1081 const auto vcs = sourceProjectContext( aSchematic );
1082
1083 std::map<KIID_PATH, std::vector<SIMULATION_MODEL_FACT>> captured;
1084 const wxString variant = aSchematic.GetCurrentVariant();
1085
1086 for( const SCH_SHEET_PATH& path : m_state->SourcePaths( aSchematic ) )
1087 captured.emplace( path.PathRef(), ExtractSimulationModelFacts( path, variant ) );
1088
1089 m_state->simulationModels = std::move( captured );
1090}
1091
1092std::vector<SIMULATION_MODEL_FACT> FACADE::SimulationModels( const KIID_PATH& aPath ) const
1093{
1094 wxASSERT( wxThread::IsMain() );
1095
1096 if( !m_state->simulationModels )
1097 throw std::logic_error( "Simulation sources have not been prepared" );
1098
1099 return m_state->simulationModels->at( aPath );
1100}
1101
1102std::optional<ITEM_VIEW> FACADE::Connection( const KIID& aItem, const KIID_PATH& aPath ) const
1103{
1104 const auto instance = Keys().FindInstance( aPath );
1105
1106 if( !instance )
1107 return std::nullopt;
1108
1109 const ITEM_KEY key{ aItem, *instance };
1110
1111 if( !m_state->Row( key ) )
1112 return std::nullopt;
1113
1114 return ITEM_VIEW( m_state, key );
1115}
1116
1117wxString ITEM_VIEW::Name( bool aIgnoreSheet ) const
1118{
1119 const auto state = m_state.lock();
1120 const auto* row = state ? state->Row( m_item ) : nullptr;
1121 return row ? state->Name( state->engine.Published().Components().at( row->component ), aIgnoreSheet ) : wxString();
1122}
1123
1124wxString ITEM_VIEW::LocalName() const
1125{
1126 const auto state = m_state.lock();
1127 const auto* row = state ? state->Row( m_item ) : nullptr;
1128 return row && row->localName != INVALID_ID ? state->engine.Keys().Name( row->localName ) : wxString();
1129}
1130
1132{
1133 const auto state = m_state.lock();
1134 const auto* row = state ? state->Row( m_item ) : nullptr;
1135 return row && row->fullLocalName != INVALID_ID ? state->engine.Keys().Name( row->fullLocalName ) : wxString();
1136}
1137
1139{
1140 const auto state = m_state.lock();
1141 const auto* row = state ? state->Row( m_item ) : nullptr;
1142 return row && row->kind == KIND::BUNDLE;
1143}
1144
1146{
1147 const auto state = m_state.lock();
1148 const auto* row = state ? state->Row( m_item ) : nullptr;
1149 return row && row->kind == KIND::SIGNAL;
1150}
1151
1153{
1154 const auto state = m_state.lock();
1155 const auto* row = state ? state->Row( m_item ) : nullptr;
1156 return !row || !row->driver;
1157}
1158
1160{
1161 const auto state = m_state.lock();
1162 const auto* row = state ? state->Row( m_item ) : nullptr;
1163 return row ? row->netCode : 0;
1164}
1165
1167{
1168 const auto state = m_state.lock();
1169 const auto* row = state ? state->Row( m_item ) : nullptr;
1170 return row ? row->subgraphCode : 0;
1171}
1172
1174{
1175 const auto state = m_state.lock();
1176 const auto* row = state ? state->Row( m_item ) : nullptr;
1177 return row && row->driver ? state->Resolve( *row->driver ) : nullptr;
1178}
1179
1180std::vector<SCH_ITEM*> ITEM_VIEW::ConnectedItems() const
1181{
1182 std::vector<SCH_ITEM*> result;
1183 const auto state = m_state.lock();
1184
1185 if( !state || !state->Row( m_item ) )
1186 return result;
1187
1188 const auto& neighbors = state->engine.Published().Auxiliary().NeighborsOf();
1189 const auto found = neighbors.find( m_item );
1190
1191 if( found == neighbors.end() )
1192 return result;
1193
1194 result.reserve( found->second.size() );
1195
1196 for( const KIID& id : found->second )
1197 {
1198 if( SCH_ITEM* item = state->Resolve( { id, m_item.inst } ) )
1199 result.push_back( item );
1200 }
1201
1202 return result;
1203}
1204
1206{
1207 const auto state = m_state.lock();
1208 const auto* row = state ? state->Row( m_item ) : nullptr;
1209 return row ? state->Sheet( row->driver ) : KIID_PATH();
1210}
1211
1213{
1214 const auto state = m_state.lock();
1215 const auto* row = state ? state->Row( m_item ) : nullptr;
1216 return row ? state->Members( row->component, m_item.inst, m_state, row ) : BUS_MEMBERS();
1217}
1218
1219std::optional<NET_VIEW> FACADE::GetSubgraphForItem( const KIID& aItem, const KIID_PATH& aPath ) const
1220{
1221 const auto instance = Keys().FindInstance( aPath );
1222
1223 if( !instance )
1224 return std::nullopt;
1225
1226 const auto* row = m_state->Row( { aItem, *instance } );
1227
1228 if( !row )
1229 return std::nullopt;
1230
1231 return NET_VIEW( m_state, row->component, *instance );
1232}
1233
1234std::vector<NET_GROUP> FACADE::GetNetMap() const
1235{
1236 const auto live = m_state->LiveInstances();
1237 std::vector<NET_GROUP> result;
1238 result.reserve( Published().ByName().size() );
1239
1240 for( const auto& [name, node] : Published().ByName() )
1241 {
1242 if( auto group = m_state->Group( node, live, m_state ) )
1243 result.push_back( std::move( *group ) );
1244 }
1245
1246 return result;
1247}
1248
1249std::vector<wxString> FACADE::NetNames() const
1250{
1251 const auto live = m_state->LiveInstances();
1252 std::vector<wxString> result;
1253 result.reserve( Published().ByName().size() );
1254
1255 for( const auto& [name, node] : Published().ByName() )
1256 {
1257 if( m_state->AnyLive( node, live ) )
1258 result.push_back( Keys().Name( name ) );
1259 }
1260
1261 return result;
1262}
1263
1264
1265std::optional<NET_GROUP> FACADE::NetByName( const wxString& aName ) const
1266{
1267 const auto node = Published().FindByName( aName );
1268
1269 if( !node )
1270 return std::nullopt;
1271
1272 return m_state->Group( *node, m_state->LiveInstances(), m_state );
1273}
1274
1275
1276std::vector<NET_GROUP> FACADE::BusWithMembers( const wxString& aName ) const
1277{
1278 const auto node = m_state->BusNode( aName );
1279
1280 if( !node )
1281 return {};
1282
1283 const auto live = m_state->LiveInstances();
1284
1285 if( !m_state->AnyLive( *node, live ) )
1286 return {};
1287
1288 const auto members = Published().MembersOf( *node );
1289 std::vector<NODE_ID> nodes( members.begin(), members.end() );
1290 nodes.push_back( *node );
1291 return m_state->Groups( std::move( nodes ), live, m_state );
1292}
1293
1294std::vector<NET_GROUP> FACADE::BundlesOf( NODE_ID aSignal ) const
1295{
1296 const auto parents = Published().ParentsOf( aSignal );
1297
1298 if( parents.empty() )
1299 return {};
1300
1301 const auto live = m_state->LiveInstances();
1302
1303 if( !m_state->AnyLive( aSignal, live ) )
1304 return {};
1305
1306 return m_state->Groups( { parents.begin(), parents.end() }, live, m_state );
1307}
1308
1309std::vector<wxString> FACADE::GetEquivalentBusNames( const wxString& aName ) const
1310{
1311 const auto node = m_state->BusNode( aName );
1312
1313 if( !node )
1314 return {};
1315
1316 const auto live = m_state->LiveInstances();
1317
1318 if( !m_state->AnyLive( *node, live ) )
1319 return {};
1320
1321 auto names = Published().EquivalentBusNames( aName );
1322 std::erase_if( names, [&]( const wxString& name )
1323 {
1324 const auto equivalent = Published().FindByName( name );
1325 return !equivalent || !m_state->AnyLive( *equivalent, live );
1326 } );
1327 return names;
1328}
1329
1331{
1332 const auto state = m_state.lock();
1333 return state ? state->engine.Keys().Instance( m_instance ) : KIID_PATH();
1334}
1335
1336wxString NET_VIEW::Name( bool aIgnoreSheet ) const
1337{
1338 const auto state = m_state.lock();
1339 const auto* net = state ? state->Net( m_component, m_instance ) : nullptr;
1340 return net ? state->Name( *net, aIgnoreSheet ) : wxString();
1341}
1342
1344{
1345 const auto state = m_state.lock();
1346 const auto* net = state ? state->Net( m_component, m_instance ) : nullptr;
1347 return net && net->content->kind == KIND::BUNDLE;
1348}
1349
1351{
1352 const auto state = m_state.lock();
1353 const auto* net = state ? state->Net( m_component, m_instance ) : nullptr;
1354 return net && net->content->kind == KIND::SIGNAL;
1355}
1356
1358{
1359 const auto state = m_state.lock();
1360 const auto* net = state ? state->Net( m_component, m_instance ) : nullptr;
1361 return net && net->content->best ? state->Resolve( net->content->best->source ) : nullptr;
1362}
1363
1365{
1366 const auto state = m_state.lock();
1367 const auto* net = state ? state->Net( m_component, m_instance ) : nullptr;
1368 return net && net->content->best ? state->Sheet( net->content->best->source ) : KIID_PATH();
1369}
1370
1372{
1373 const auto state = m_state.lock();
1374 return state && state->Net( m_component, m_instance )
1375 ? state->Members( m_component, m_instance, m_state ) : BUS_MEMBERS();
1376}
1377
1378std::vector<SCH_ITEM*> NET_VIEW::Items() const
1379{
1380 std::vector<SCH_ITEM*> result;
1381 const auto state = m_state.lock();
1382
1383 if( !state || !state->Net( m_component, m_instance ) )
1384 return result;
1385
1386 const auto& ids = state->netItems.at( m_component )->instances.at( m_instance );
1387 result.reserve( ids.size() );
1388
1389 for( const KIID& id : ids )
1390 {
1391 if( SCH_ITEM* item = state->Resolve( { id, m_instance } ) )
1392 result.push_back( item );
1393 }
1394
1395 return result;
1396}
1397} // namespace SCH_CONNECTIVITY
const char * name
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
bool VoidListAllowed()
void SaveInString(wxString *aOutputString)
Save the description in a buffer.
static void SetAltInstance(DS_DATA_MODEL *aLayout=nullptr)
Set an alternate instance of DS_DATA_MODEL.
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
Definition kiid.h:46
NET_SETTINGS stores various net-related settings in a project context.
void ClearCacheForNet(const wxString &netName)
Clears the net cache and cached bus classes derived from that net.
void ClearNetclassLabelAssignment(const wxString &netName)
Clears a specific net name to netclass assignment Calling user is responsible for resetting the effec...
void SetNetclassLabelAssignment(const wxString &netName, const std::set< wxString > &netclasses)
Sets a net name to netclasses assignment Calling user is responsible for resetting the effective netc...
const std::map< wxString, std::set< wxString > > & GetNetclassLabelAssignments() const
Gets all current net name to netclasses assignments.
wxString GetTypeAsString() const
const VECTOR2D & GetSizeMils() const
Definition page_info.h:146
bool IsPortrait() const
Definition page_info.h:124
std::shared_ptr< NET_SETTINGS > & NetSettings()
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:177
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:201
Holds all the data relating to one schematic.
Definition schematic.h:149
SCH_CONNECTIVITY::NETCHAIN_MANAGER & NetChains() const
Definition schematic.h:317
wxString GetVariantDescription(const wxString &aVariantName) const
Return the description for a variant.
SCH_SHEET_LIST BuildSheetListSortedByPageNumbers() const
const std::vector< std::shared_ptr< BUS_ALIAS > > & GetAllBusAliases() const
Definition schematic.h:349
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:171
wxString GetCurrentVariant() const
Return the current variant being edited.
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition schematic.h:289
SCH_SHEET & Root() const
Definition schematic.h:200
SCH_SHEET_PATH & CurrentSheet() const
Definition schematic.h:304
Base class for a bus or wire entry.
const AREA_INDEX & RuleAreasOf() const
Owns one key/version session and its current stage evaluations; main-thread use only.
Model-owned source resolver.
std::optional< NET_GROUP > NetByName(const wxString &aName) const
void Update(SCHEMATIC &aSchematic, bool aRebuild=false)
std::optional< NET_VIEW > GetSubgraphForItem(const KIID &aItem, const KIID_PATH &aPath) const
void Recalculate(SCHEMATIC &aSchematic, bool aRebuild=false, const std::function< void(SCH_ITEM *)> &aChangedHandler={})
Update the complete model and apply netclasses, dangling flags and dirty-state clearing.
void ApplyNetclasses(NET_SETTINGS &aSettings) const
Replace label-derived assignments from a complete publication; invalidate changed net caches.
std::vector< NET_GROUP > GetNetMap() const
Owned query-time groups in canonical name order, with unique instances in KIID_PATH order.
std::vector< TEXT_CHECK_FACT > TextChecks(const KIID_PATH &aPath, bool aDrawingSheet=false) const
std::vector< wxString > NetNames() const
const SESSION_KEYS & Keys() const
void PrepareSimulationModels(SCHEMATIC &aSchematic)
const ENGINE & Engine() const
void updateModel(SCHEMATIC &aSchematic, const SCH_SHEET_LIST &aPaths, bool aRebuild)
Capture the text context and advance the text epoch when it or an external source changed.
void PrepareTextChecks(SCHEMATIC &aSchematic, bool aIncludeDrawingSheet=false)
std::vector< SIMULATION_MODEL_FACT > SimulationModels(const KIID_PATH &aPath) const
bool UpdateShadow(SCHEMATIC &aSchematic, const SCH_SHEET_LIST &aPaths, bool aRebuild=false)
std::optional< ITEM_VIEW > Connection(const KIID &aItem, const KIID_PATH &aPath) const
const PUBLICATION & Published() const
SUBSCRIPTION Subscribe(std::function< void(const CHANGE_SET &)> aListener)
std::vector< wxString > GetEquivalentBusNames(const wxString &aName) const
std::vector< NET_GROUP > BundlesOf(NODE_ID aSignal) const
std::shared_ptr< FACADE_STATE > m_state
std::vector< NET_GROUP > BusWithMembers(const wxString &aName) const
Excludes derived graph text and shares dynamic source values through nested resolvers.
Definition conn_text.h:34
BUS_MEMBERS Members() const
wxString Name(bool aIgnoreSheet=false) const
std::weak_ptr< const FACADE_STATE > m_state
Definition conn_facade.h:63
std::vector< SCH_ITEM * > ConnectedItems() const
void Rebuild(const NETCHAIN_INPUT &aConnectivity, const std::function< void(NETCHAIN_MANAGER &)> &aBeforePublish={})
void ApplyNetChainNetclasses()
Mirror each committed net chain's netclass override into the project NET_SETTINGS as a chain-derived ...
wxString Name(bool aIgnoreSheet=false) const
BUS_MEMBERS Members() const
SCH_ITEM * Driver() const
std::vector< SCH_ITEM * > Items() const
std::weak_ptr< const FACADE_STATE > m_state
Definition conn_facade.h:91
PUBLICATION_HOLD(const FACADE &aFacade)
std::weak_ptr< FACADE_STATE > m_state
Main-thread publication.
std::span< const NODE_ID > MembersOf(NODE_ID aBundle) const
std::vector< wxString > EquivalentBusNames(const wxString &aName) const
const AUXILIARY & Auxiliary() const
std::span< const NODE_ID > ParentsOf(NODE_ID aSignal) const
const CHANGE_SET & Changes() const
std::optional< NODE_ID > FindByName(const wxString &aName) const
static bool Active()
True inside a render scope, unless an INPUT_TEXT_SCOPE is also active.
Definition conn_text.h:69
Session IDs are dense handles, never a canonical ordering.
Definition conn_keys.h:146
const wxString & Name(NAME_ID aId) const
Definition conn_keys.h:163
const KIID_PATH & Instance(INST_ID aId) const
Definition conn_keys.h:162
std::optional< INST_ID > FindInstance(const KIID_PATH &aPath) const
Definition conn_keys.h:160
Main-thread registration owner.
SUBSCRIPTION & operator=(const SUBSCRIPTION &)=delete
std::weak_ptr< FACADE_STATE > m_state
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
virtual bool GetExcludedFromPosFiles(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const
Definition sch_item.h:286
void SetConnectivityDirty(bool aDirty=true)
Set the dirty flag.
Definition sch_item.cpp:309
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
static wxString MakeKey(const wxString &aName, uint32_t aComponent)
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:144
uint64_t ConnectivityId() const
Process-local lifetime identity; file UUIDs can be shared by distinct screens.
Definition sch_screen.h:201
uint64_t ConnectivityRevision() const
The only change signal that the connectivity engine reads from this screen.
Definition sch_screen.h:181
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
const wxString & GetFileName() const
Definition sch_screen.h:157
std::weak_ptr< const CONNECTIVITY_SOURCE > ConnectivitySource() const
Definition sch_screen.h:208
SCH_ITEM * GetConnectivityItem(const KIID &aId) const
Resolve a drawing item or a connectable child on this screen; ambiguous IDs return null.
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:168
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
const KIID_PATH & PathRef() const
Borrow the cached path until this sheet path is modified or destroyed.
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition sch_sheet.h:91
bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
int CountSheets() const
Count the number of sheets found in "this" sheet including all of the subsheets.
bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flags.
bool GetExcludedFromBoard(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Definition sch_sheet.h:475
const std::vector< SCH_SHEET_INSTANCE > & GetInstances() const
Definition sch_sheet.h:519
const wxString & GetCompany() const
Definition title_block.h:93
const wxString & GetRevision() const
Definition title_block.h:83
const wxString & GetDate() const
Definition title_block.h:73
const wxString & GetComment(int aIdx) const
const wxString & GetTitle() const
Definition title_block.h:60
bool equivalent(SIM_MODEL::DEVICE_T a, SIM_MODEL::DEVICE_T b)
@ NO_RECURSE
Definition eda_item.h:52
void Reset() override
Value keys and the key session of the schematic connectivity engine.
std::map< wxString, std::vector< wxString > > BUS_ALIASES
Bus alias table, from alias name to member texts.
Definition conn_bus.h:40
uint32_t INST_ID
Session handle of a sheet instance KIID_PATH.
Definition conn_keys.h:41
std::vector< SIMULATION_MODEL_FACT > ExtractSimulationModelFacts(const SCH_SHEET_PATH &aPath, const wxString &aVariantName)
std::vector< TEXT_CHECK_FACT > ExtractTextChecks(const SCH_SCREEN &aScreen, const SCH_SHEET_PATH &aPath)
uint32_t NAME_ID
Session handle of a name, ordered by UTF-8 value through NAME_LESS.
Definition conn_keys.h:42
uint64_t SCREEN_ID
Process-local SCH_SCREEN::ConnectivityId(), never a file UUID.
Definition conn_keys.h:44
uint32_t NODE_ID
Session handle of a NODE_KEY graph node.
Definition conn_keys.h:43
std::vector< TEXT_CHECK_FACT > ExtractDrawingSheetTextChecks(const SCH_SCREEN &aScreen, const SCH_SHEET_PATH &aPath)
TEXT_EVAL::ENVIRONMENT TEXT_ENVIRONMENT
Definition conn_text.h:27
BUS_ALIGNMENT Align(const BUS_SCHEMA &aLeft, const BUS_SCHEMA &aRight)
Match the leaves of aLeft to the leaves of aRight.
Definition conn_bus.cpp:282
constexpr uint32_t INVALID_ID
Marks an unset handle.
Definition conn_keys.h:47
wxString GetContextPath()
Return the current context path for repo-scoped VCS queries.
bool GetContextIsFile()
File/directory classification captured when the current context was activated.
STL namespace.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
Member correspondence between two bus schemas.
Definition conn_bus.h:181
std::vector< size_t > unmappedLeft
Left leaf ordinals without a right partner.
Definition conn_bus.h:183
std::vector< std::pair< size_t, size_t > > matched
Pairs of left and right leaf ordinals.
Definition conn_bus.h:182
Query-time snapshot; reacquire after Update.
Difference between two publications.
std::vector< ITEM_KEY > changedItems
Items whose row, island, rule area, source or text changed.
std::shared_ptr< const COMPONENT_CONTENT > content
std::map< INST_ID, std::vector< KIID > > instances
std::optional< std::vector< TEXT_CHECK_FACT > > drawingSheet
std::vector< TEXT_CHECK_FACT > items
std::map< NODE_ID, std::shared_ptr< const NET_ITEMS > > netItems
std::optional< NODE_ID > BusNode(const wxString &aName) const
std::vector< NET_GROUP > Groups(std::vector< NODE_ID > aNodes, std::span< const INST_ID > aLive, const std::weak_ptr< const FACADE_STATE > &aState) const
std::vector< INST_ID > LiveInstances() const
const ITEM_RESULT * Row(const ITEM_KEY &aItem) const
KIID_PATH Sheet(const std::optional< ITEM_KEY > &aDriver) const
const PUBLISHED_COMPONENT * Net(NODE_ID aNode, INST_ID aInstance) const
std::optional< NET_GROUP > Group(NODE_ID aNode, std::span< const INST_ID > aLive, const std::weak_ptr< const FACADE_STATE > &aState) const
wxString Name(const PUBLISHED_COMPONENT &aComponent, bool aIgnoreSheet) const
std::map< INST_ID, std::weak_ptr< const SCH_SCREEN::CONNECTIVITY_SOURCE > > sources
bool AnyLive(NODE_ID aNode, std::span< const INST_ID > aLive) const
std::map< uint64_t, std::function< void(const CHANGE_SET &)> > listeners
BUS_MEMBERS Members(NODE_ID aNode, INST_ID aInstance, const std::weak_ptr< const FACADE_STATE > &aState, const ITEM_RESULT *aRow=nullptr) const
bool Current(const SCH_SCREEN &aScreen) const
SCH_SCREEN * Screen(const std::weak_ptr< const SCH_SCREEN::CONNECTIVITY_SOURCE > &aSource) const
SCH_ITEM * Resolve(const ITEM_KEY &aItem) const
std::optional< MODEL_TEXT_CONTEXT > textContext
SCH_SHEET_LIST SourcePaths(SCHEMATIC &aSchematic) const
std::optional< std::map< KIID_PATH, std::vector< SIMULATION_MODEL_FACT > > > simulationModels
SCH_SCREEN * Screen(INST_ID aInstance) const
std::optional< std::map< KIID_PATH, TEXT_CHECKS > > textChecks
One item or pin in one sheet instance.
Definition conn_keys.h:77
KIID item
The item or pin KIID.
Definition conn_keys.h:78
INST_ID inst
The sheet instance that shows the item.
Definition conn_keys.h:79
Published connection of one item on one sheet instance.
Orders keys by value through SESSION_KEYS::Less().
Definition conn_keys.h:255
Orders name handles by UTF-8 value.
Definition conn_keys.h:246
Immediate-use netchain input; shared-screen items are qualified by their instance.
std::pmr::monotonic_buffer_resource storage
One published net or bus with its identity.
NAME_ID name
Unique name, invalid without a claim.
std::shared_ptr< const COMPONENT_CONTENT > content
One member position of a bus.
Definition conn_keys.h:127
ITEM_KEY bundleDriver
The source item of the claim that defines the leaf order.
Definition conn_keys.h:128
std::string path
wxString result
Test unit parsing edge cases and error handling.
@ SCH_LINE_T
Definition typeinfo.h:159
@ SCH_DIRECTIVE_LABEL_T
Definition typeinfo.h:167
@ SCH_LABEL_T
Definition typeinfo.h:163
@ SCH_HIER_LABEL_T
Definition typeinfo.h:165
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:158
@ SCH_SHEET_PIN_T
Definition typeinfo.h:170
@ SCH_BUS_WIRE_ENTRY_T
Definition typeinfo.h:157
@ SCH_GLOBAL_LABEL_T
Definition typeinfo.h:164
@ SCH_PIN_T
Definition typeinfo.h:149
VECTOR2< double > VECTOR2D
Definition vector2d.h:682