KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_issue20173_paste_subsheet.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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, you may find one here:
18 * https://www.gnu.org/licenses/gpl-3.0.en.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
41
44
45#include <connection_graph.h>
46#include <schematic.h>
47#include <sch_sheet.h>
48#include <sch_screen.h>
49#include <sch_symbol.h>
51#include <locale_io.h>
52
53
55{
58
60 std::unique_ptr<SCHEMATIC> m_schematic;
61};
62
63
68std::map<KIID, wxString> GetSymbolReferences( const SCH_SHEET_PATH& aPath )
69{
70 std::map<KIID, wxString> refs;
71
72 if( !aPath.LastScreen() )
73 return refs;
74
75 for( SCH_ITEM* item : aPath.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
76 {
77 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
78
79 // Skip power symbols (references starting with #)
80 wxString ref = symbol->GetRef( &aPath );
81
82 if( !ref.IsEmpty() && ref[0] != '#' )
83 refs[symbol->m_Uuid] = ref;
84 }
85
86 return refs;
87}
88
89
96BOOST_FIXTURE_TEST_CASE( Issue20173PruningAfterPaste, ISSUE20173_FIXTURE )
97{
99
100 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
101
102 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
103
104 // Find the ch1 subsheet
105 SCH_SHEET_PATH ch1Path;
106 SCH_SHEET* ch1Sheet = nullptr;
107
108 for( const SCH_SHEET_PATH& path : sheets )
109 {
110 if( path.size() > 1 )
111 {
112 ch1Path = path;
113 ch1Sheet = path.Last();
114 break;
115 }
116 }
117
118 BOOST_REQUIRE( ch1Sheet != nullptr );
119
120 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
121 BOOST_REQUIRE( sharedScreen != nullptr );
122
123 // Set up proper instances for ch1 (in case the loaded data has stale UUIDs)
124 std::map<KIID, wxString> originalRefs;
125
126 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
127 {
128 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
129 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
130
131 if( ref.IsEmpty() || ref[0] == '#' )
132 continue;
133
134 symbol->SetRef( &ch1Path, ref );
135 originalRefs[symbol->m_Uuid] = ref;
136 }
137
138 // Create ch2 with shared screen (simulating paste)
139 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
140 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
141 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
142 ch2Sheet->SetScreen( sharedScreen );
143 ch2Sheet->SetPosition( ch1Sheet->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 1000 ), 0 ) );
144
145 // Add to root and refresh hierarchy
146 m_schematic->RootScreen()->Append( ch2Sheet );
147 m_schematic->RefreshHierarchy();
148
149 // Get updated hierarchy
150 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
151 SCH_SHEET_PATH ch2Path;
152
153 for( const SCH_SHEET_PATH& path : sheets )
154 {
155 if( path.size() > 1 && path.Last() == ch2Sheet )
156 {
157 ch2Path = path;
158 break;
159 }
160 }
161
162 BOOST_REQUIRE( ch2Path.size() > 1 );
163
164 // Add ch2 instances with different references
165 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
166 {
167 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
168 wxString ch1Ref = symbol->GetRef( &ch1Path );
169
170 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
171 continue;
172
173 // Create ch2 reference (R1 -> R101)
174 wxString ch2Ref = ch1Ref;
175
176 if( ch2Ref.length() > 1 )
177 {
178 wxString prefix = ch2Ref.substr( 0, 1 );
179 long num = 0;
180
181 if( ch2Ref.substr( 1 ).ToLong( &num ) )
182 ch2Ref = prefix + wxString::Format( "%ld", num + 100 );
183 }
184
185 symbol->SetRef( &ch2Path, ch2Ref );
186 }
187
188 // Verify instances are set up correctly before pruning
189 BOOST_TEST_MESSAGE( "Before pruning:" );
190
191 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
192 {
193 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
194
195 if( symbol->GetRef( &ch1Path )[0] == '#' )
196 continue;
197
198 BOOST_TEST_MESSAGE( " " << symbol->m_Uuid.AsString() << " ch1=" << symbol->GetRef( &ch1Path )
199 << " ch2=" << symbol->GetRef( &ch2Path ) );
200 break;
201 }
202
203 // Now call the pruning that happens after paste
204 // This is what SCH_EDITOR_CONTROL::Paste does at line 2615
205 SCH_SCREENS allScreens( m_schematic->Root() );
206 allScreens.PruneOrphanedSymbolInstances( m_schematic->Project().GetProjectName(), sheets );
207
208 BOOST_TEST_MESSAGE( "After pruning:" );
209
210 // Verify ch1 instances are still intact after pruning
211 bool ch1InstancesIntact = true;
212
213 for( const auto& [uuid, originalRef] : originalRefs )
214 {
215 // Find the symbol
216 SCH_SYMBOL* symbol = nullptr;
217
218 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
219 {
220 if( item->m_Uuid == uuid )
221 {
222 symbol = static_cast<SCH_SYMBOL*>( item );
223 break;
224 }
225 }
226
227 if( !symbol )
228 continue;
229
230 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
231 wxString ch2RefAfter = symbol->GetRef( &ch2Path );
232
233 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " ch1=" << ch1RefAfter << " ch2="
234 << ch2RefAfter << " (original=" << originalRef << ")" );
235
236 if( ch1RefAfter != originalRef )
237 {
238 BOOST_TEST_MESSAGE( " MISMATCH: ch1 reference changed from " << originalRef << " to "
239 << ch1RefAfter );
240 ch1InstancesIntact = false;
241 }
242 }
243
244 BOOST_CHECK_MESSAGE( ch1InstancesIntact,
245 "CH1 instances should be preserved after paste and pruning" );
246}
247
248
255BOOST_FIXTURE_TEST_CASE( Issue20173ClearAnnotationFieldCorruption, ISSUE20173_FIXTURE )
256{
258
259 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
260
261 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
262
263 // Find the ch1 subsheet
264 SCH_SHEET_PATH ch1Path;
265 SCH_SHEET* ch1Sheet = nullptr;
266
267 for( const SCH_SHEET_PATH& path : sheets )
268 {
269 if( path.size() > 1 )
270 {
271 ch1Path = path;
272 ch1Sheet = path.Last();
273 break;
274 }
275 }
276
277 BOOST_REQUIRE( ch1Sheet != nullptr );
278
279 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
280 BOOST_REQUIRE( sharedScreen != nullptr );
281
282 // Set up proper instances for ch1 (fix any stale UUID issues from loading)
283 std::map<KIID, wxString> ch1OriginalRefs;
284
285 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
286 {
287 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
288 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
289
290 if( ref.IsEmpty() || ref[0] == '#' )
291 continue;
292
293 symbol->SetRef( &ch1Path, ref );
294 ch1OriginalRefs[symbol->m_Uuid] = ref;
295 }
296
297 // Create ch2 with shared screen
298 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
299 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
300 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
301 ch2Sheet->SetScreen( sharedScreen );
302
303 m_schematic->RootScreen()->Append( ch2Sheet );
304 m_schematic->RefreshHierarchy();
305
306 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
307
308 SCH_SHEET_PATH ch2Path;
309
310 for( const SCH_SHEET_PATH& path : sheets )
311 {
312 if( path.size() > 1 && path.Last() == ch2Sheet )
313 {
314 ch2Path = path;
315 break;
316 }
317 }
318
319 BOOST_REQUIRE( ch2Path.size() > 1 );
320
321 // Add ch2 instances and call ClearAnnotation (simulating paste with !forceKeepAnnotations)
322 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
323 {
324 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
325 wxString ch1Ref = symbol->GetRef( &ch1Path );
326
327 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
328 continue;
329
330 // Add instance for ch2 (like updatePastedSymbol does)
331 symbol->SetRef( &ch2Path, ch1Ref );
332
333 // Now call ClearAnnotation for ch2 path (like updatePastedSymbol does when !forceKeepAnnotations)
334 symbol->ClearAnnotation( &ch2Path, false );
335 }
336
337 // Verify ch1 references are unchanged after ClearAnnotation on ch2
338 bool ch1RefsPreserved = true;
339
340 for( const auto& [uuid, originalRef] : ch1OriginalRefs )
341 {
342 SCH_SYMBOL* symbol = nullptr;
343
344 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
345 {
346 if( item->m_Uuid == uuid )
347 {
348 symbol = static_cast<SCH_SYMBOL*>( item );
349 break;
350 }
351 }
352
353 if( !symbol )
354 continue;
355
356 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
357
358 if( ch1RefAfter != originalRef )
359 {
360 BOOST_TEST_MESSAGE( "Symbol " << uuid.AsString() << " ch1 reference changed from "
361 << originalRef << " to " << ch1RefAfter
362 << " after ClearAnnotation on ch2" );
363 ch1RefsPreserved = false;
364 }
365 }
366
367 BOOST_CHECK_MESSAGE( ch1RefsPreserved,
368 "CH1 references should be preserved after ClearAnnotation on CH2" );
369}
370
371
379BOOST_FIXTURE_TEST_CASE( Issue20173FieldTextCorruption, ISSUE20173_FIXTURE )
380{
382
383 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
384
385 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
386
387 // Find the ch1 subsheet
388 SCH_SHEET_PATH ch1Path;
389 SCH_SHEET* ch1Sheet = nullptr;
390
391 for( const SCH_SHEET_PATH& path : sheets )
392 {
393 if( path.size() > 1 )
394 {
395 ch1Path = path;
396 ch1Sheet = path.Last();
397 break;
398 }
399 }
400
401 BOOST_REQUIRE( ch1Sheet != nullptr );
402
403 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
404 BOOST_REQUIRE( sharedScreen != nullptr );
405
406 // Capture original field text values (these are what GetRef falls back to)
407 std::map<KIID, wxString> originalFieldText;
408
409 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
410 {
411 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
412 wxString ref = symbol->GetField( FIELD_T::REFERENCE )->GetText();
413
414 if( !ref.IsEmpty() && ref[0] != '#' )
415 originalFieldText[symbol->m_Uuid] = ref;
416 }
417
418 BOOST_REQUIRE( originalFieldText.size() > 0 );
419
420 BOOST_TEST_MESSAGE( "Original field text values:" );
421
422 for( const auto& [uuid, ref] : originalFieldText )
423 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " -> " << ref );
424
425 // Create ch2 with shared screen (simulating paste)
426 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
427 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
428 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
429 ch2Sheet->SetScreen( sharedScreen );
430
431 m_schematic->RootScreen()->Append( ch2Sheet );
432 m_schematic->RefreshHierarchy();
433
434 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
435
436 SCH_SHEET_PATH ch2Path;
437
438 for( const SCH_SHEET_PATH& path : sheets )
439 {
440 if( path.size() > 1 && path.Last() == ch2Sheet )
441 {
442 ch2Path = path;
443 break;
444 }
445 }
446
447 BOOST_REQUIRE( ch2Path.size() > 1 );
448
449 // Simulate what updatePastedSymbol does:
450 // 1. Add instance for new path
451 // 2. Call ClearAnnotation for new path
452 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
453 {
454 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
455 wxString fieldRef = symbol->GetField( FIELD_T::REFERENCE )->GetText();
456
457 if( fieldRef.IsEmpty() || fieldRef[0] == '#' )
458 continue;
459
460 // Add instance for ch2 (like AddHierarchicalReference does)
461 symbol->SetRef( &ch2Path, fieldRef );
462
463 // Now call ClearAnnotation for ch2 path (like updatePastedSymbol does)
464 symbol->ClearAnnotation( &ch2Path, false );
465 }
466
467 // Check if field text is corrupted
468 BOOST_TEST_MESSAGE( "Field text after ClearAnnotation on ch2:" );
469
470 bool fieldTextCorrupted = false;
471
472 for( const auto& [uuid, originalRef] : originalFieldText )
473 {
474 SCH_SYMBOL* symbol = nullptr;
475
476 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
477 {
478 if( item->m_Uuid == uuid )
479 {
480 symbol = static_cast<SCH_SYMBOL*>( item );
481 break;
482 }
483 }
484
485 if( !symbol )
486 continue;
487
488 wxString currentFieldText = symbol->GetField( FIELD_T::REFERENCE )->GetText();
489
490 BOOST_TEST_MESSAGE( " " << uuid.AsString() << " -> " << currentFieldText
491 << " (was " << originalRef << ")" );
492
493 if( currentFieldText != originalRef )
494 {
495 fieldTextCorrupted = true;
496 BOOST_TEST_MESSAGE( " CORRUPTED!" );
497 }
498 }
499
500 // The bug: ClearAnnotation modifies field text even when called for a specific path
501 // This causes GetRef to return wrong value when falling back to field text
502 BOOST_CHECK_MESSAGE( !fieldTextCorrupted,
503 "Field text should NOT be corrupted by ClearAnnotation on different path" );
504}
505
506
513BOOST_FIXTURE_TEST_CASE( Issue20173SharedScreenInstances, ISSUE20173_FIXTURE )
514{
516
517 KI_TEST::LoadSchematic( m_settingsManager, "issue20173/issue20173", m_schematic );
518
519 SCH_SHEET_LIST sheets = m_schematic->BuildSheetListSortedByPageNumbers();
520
521 // Find the ch1 subsheet
522 SCH_SHEET_PATH ch1Path;
523 SCH_SHEET* ch1Sheet = nullptr;
524
525 for( const SCH_SHEET_PATH& path : sheets )
526 {
527 if( path.size() > 1 )
528 {
529 ch1Path = path;
530 ch1Sheet = path.Last();
531 break;
532 }
533 }
534
535 BOOST_REQUIRE( ch1Sheet != nullptr );
536
537 SCH_SCREEN* sharedScreen = ch1Sheet->GetScreen();
538 BOOST_REQUIRE( sharedScreen != nullptr );
539
540 // Get root path for adding new sheet
541 SCH_SHEET_PATH rootPath;
542 rootPath.push_back( &m_schematic->Root() );
543
544 // Create ch2 with shared screen
545 SCH_SHEET* ch2Sheet = new SCH_SHEET( m_schematic.get() );
546 ch2Sheet->GetField( FIELD_T::SHEET_NAME )->SetText( "ch2" );
547 ch2Sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( ch1Sheet->GetFileName() );
548 ch2Sheet->SetScreen( sharedScreen );
549 ch2Sheet->SetPosition( ch1Sheet->GetPosition() + VECTOR2I( schIUScale.MilsToIU( 1000 ), 0 ) );
550
551 // Manually add ch2 to root screen
552 m_schematic->RootScreen()->Append( ch2Sheet );
553 m_schematic->RefreshHierarchy();
554
555 // Rebuild sheets after adding ch2
556 sheets = m_schematic->BuildSheetListSortedByPageNumbers();
557
558 // Find ch2 path from the hierarchy (don't construct manually)
559 SCH_SHEET_PATH ch2Path;
560
561 for( const SCH_SHEET_PATH& path : sheets )
562 {
563 if( path.size() > 1 && path.Last() == ch2Sheet )
564 {
565 ch2Path = path;
566 break;
567 }
568 }
569
570 BOOST_REQUIRE_MESSAGE( ch2Path.size() > 1, "Should find ch2 in hierarchy" );
571
572 // First, ensure all symbols have proper instances for ch1Path
573 // (The loaded schematic might have stale instance data with old sheet UUIDs)
574 int symbolIndex = 0;
575
576 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
577 {
578 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
579
580 // Skip power symbols
581 wxString currentRef = symbol->GetField( FIELD_T::REFERENCE )->GetText();
582
583 if( currentRef.IsEmpty() || currentRef[0] == '#' )
584 continue;
585
586 // Set up proper ch1 reference using the current field text
587 symbol->SetRef( &ch1Path, currentRef );
588 symbolIndex++;
589 }
590
591 BOOST_TEST_MESSAGE( "Set up " << symbolIndex << " symbols with ch1 instances" );
592
593 // Now set different references for ch2
594 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
595 {
596 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
597
598 wxString ch1Ref = symbol->GetRef( &ch1Path );
599
600 // Skip power symbols
601 if( ch1Ref.IsEmpty() || ch1Ref[0] == '#' )
602 continue;
603
604 // Add a different reference for ch2 (R1 -> R101, D1 -> D101, etc.)
605 wxString ch2Ref = ch1Ref;
606
607 if( ch2Ref.length() > 1 )
608 {
609 wxString prefix = ch2Ref.substr( 0, 1 );
610 long num = 0;
611
612 if( ch2Ref.substr( 1 ).ToLong( &num ) )
613 ch2Ref = prefix + wxString::Format( "%ld", num + 100 );
614 }
615
616 symbol->SetRef( &ch2Path, ch2Ref );
617
618 // Verify ch1 reference is unchanged
619 wxString ch1RefAfter = symbol->GetRef( &ch1Path );
620 BOOST_CHECK_MESSAGE( ch1Ref == ch1RefAfter,
621 "Setting ch2 reference should not change ch1 reference for symbol "
622 << symbol->m_Uuid.AsString() );
623
624 // Verify ch2 has its own reference
625 wxString ch2RefAfter = symbol->GetRef( &ch2Path );
626 BOOST_CHECK_MESSAGE( ch2Ref == ch2RefAfter,
627 "ch2 should have its own reference for symbol "
628 << symbol->m_Uuid.AsString() );
629 }
630
631 // Debug: Print ch1 and ch2 paths
632 BOOST_TEST_MESSAGE( "ch1Path: " << ch1Path.Path().AsString() );
633 BOOST_TEST_MESSAGE( "ch2Path: " << ch2Path.Path().AsString() );
634
635 // Debug: Print instances for first non-power symbol before UpdateAllScreenReferences
636 BOOST_TEST_MESSAGE( "Before UpdateAllScreenReferences:" );
637
638 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
639 {
640 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
641
642 if( symbol->GetRef( &ch1Path )[0] == '#' )
643 continue;
644
645 BOOST_TEST_MESSAGE( "Symbol " << symbol->m_Uuid.AsString() << " instances:" );
646
647 for( const SCH_SYMBOL_INSTANCE& inst : symbol->GetInstances() )
648 {
649 BOOST_TEST_MESSAGE( " Path: " << inst.m_Path.AsString() << " -> " << inst.m_Reference );
650 }
651
652 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
653 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
654 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
655 break; // Only print first symbol for brevity
656 }
657
658 // Now test UpdateAllScreenReferences doesn't corrupt the other instance
660
661 BOOST_TEST_MESSAGE( "After ch2Path.UpdateAllScreenReferences():" );
662
663 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
664 {
665 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
666
667 if( symbol->GetRef( &ch1Path )[0] == '#' )
668 continue;
669
670 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
671 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
672 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
673 break;
674 }
675
677
678 BOOST_TEST_MESSAGE( "After ch1Path.UpdateAllScreenReferences():" );
679
680 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
681 {
682 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
683
684 if( symbol->GetRef( &ch1Path )[0] == '#' )
685 continue;
686
687 BOOST_TEST_MESSAGE( " Field text: " << symbol->GetField( FIELD_T::REFERENCE )->GetText() );
688 BOOST_TEST_MESSAGE( " GetRef(ch1): " << symbol->GetRef( &ch1Path ) );
689 BOOST_TEST_MESSAGE( " GetRef(ch2): " << symbol->GetRef( &ch2Path ) );
690 break;
691 }
692
693 // Verify references are still correct after switching
694 for( SCH_ITEM* item : sharedScreen->Items().OfType( SCH_SYMBOL_T ) )
695 {
696 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
697
698 if( symbol->GetRef( &ch1Path )[0] == '#' )
699 continue;
700
701 // Check that instances exist and are different
702 wxString ch1Ref = symbol->GetRef( &ch1Path );
703 wxString ch2Ref = symbol->GetRef( &ch2Path );
704
705 // Since we set ch2 = ch1 + 100, they should be different
706 BOOST_CHECK_MESSAGE( ch1Ref != ch2Ref,
707 "ch1 and ch2 should have different references after navigation" );
708 }
709}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
const KIID m_Uuid
Definition eda_item.h:522
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
wxString AsString() const
Definition kiid.cpp:356
wxString AsString() const
Definition kiid.cpp:246
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:118
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:747
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:118
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...
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
SCH_SCREEN * LastScreen()
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
size_t size() const
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetPosition(const VECTOR2I &aPosition) override
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
VECTOR2I GetPosition() const override
Definition sch_sheet.h:496
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Schematic symbol object.
Definition sch_symbol.h:76
const std::vector< SCH_SYMBOL_INSTANCE > & GetInstances() const
Definition sch_symbol.h:135
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void ClearAnnotation(const SCH_SHEET_PATH *aSheetPath, bool aResetPrefix)
Clear exiting symbol annotation.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::vector< FAB_LAYER_COLOR > dummy
std::unique_ptr< SCHEMATIC > m_schematic
A simple container for schematic symbol instance information.
@ REFERENCE
Field Reference of part, i.e. "IC21".
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_FIXTURE_TEST_CASE(Issue20173PruningAfterPaste, ISSUE20173_FIXTURE)
Test that simulates the paste flow more closely, including instance pruning.
std::map< KIID, wxString > GetSymbolReferences(const SCH_SHEET_PATH &aPath)
Helper function to get all symbol references for a given sheet path.
std::string path
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
@ SCH_SYMBOL_T
Definition typeinfo.h:176
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695