Move schematic sheet instance information into file sheet definition.

This will make it possible to maintain sheet instance information when
copying and pasting from any sheet other that the root sheet of a
project.

Setting and getting sheet page numbers must now be performed using a
sheet path.  This was done to ensure that the instance paths were not
getting changed unexpectedly from different code paths.
This commit is contained in:
Wayne Stambaugh 2022-11-22 14:35:27 -05:00
parent 226dc9de78
commit 4a27d856f7
18 changed files with 325 additions and 157 deletions

View File

@ -172,7 +172,7 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataToWindow()
instance.push_back( m_sheet );
wxString nextPageNumber = m_sheet->GetPageNumber( instance );
wxString nextPageNumber = instance.GetPageNumber();
m_pageNumberTextCtrl->ChangeValue( nextPageNumber );
@ -378,12 +378,7 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow()
instance.push_back( m_sheet );
if( m_sheet->IsNew() )
{
m_sheet->AddInstance( instance );
}
m_sheet->SetPageNumber( instance, m_pageNumberTextCtrl->GetValue() );
instance.SetPageNumber( m_pageNumberTextCtrl->GetValue() );
m_frame->TestDanglingEnds();

View File

@ -453,7 +453,8 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221002 )
sheetList.UpdateSymbolInstances( Schematic().RootScreen()->GetSymbolInstances() );
sheetList.UpdateSheetInstances( Schematic().RootScreen()->GetSheetInstances() );
if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221110 )
sheetList.UpdateSheetInstances( Schematic().RootScreen()->GetSheetInstances() );
}
Schematic().ConnectionGraph()->Reset();

View File

@ -125,7 +125,7 @@ void HIERARCHY_NAVIG_PANEL::buildHierarchyTree( SCH_SHEET_PATH* aList, const wxT
aList->push_back( sheet );
wxString sheetName = formatPageString( sheet->GetFields()[SHEETNAME].GetShownText(),
sheet->GetPageNumber( *aList ) );
aList->GetPageNumber() );
wxTreeItemId child = m_tree->AppendItem( aParent, sheetName, 0, 1 );
m_tree->SetItemData( child, new TREE_ITEM_DATA( *aList ) );
@ -305,7 +305,7 @@ wxString HIERARCHY_NAVIG_PANEL::getRootString()
SCH_SHEET_PATH rootPath;
rootPath.push_back( rootSheet );
return formatPageString ( _( "Root" ), rootSheet->GetPageNumber( rootPath ) );
return formatPageString ( _( "Root" ), rootPath.GetPageNumber() );
}

View File

@ -669,10 +669,10 @@ void SCH_EDIT_FRAME::CreateScreens()
// Don't leave root page number empty
SCH_SHEET_PATH rootSheetPath;
rootSheetPath.push_back( &m_schematic->Root() );
rootSheetPath.push_back( rootSheet );
m_schematic->RootScreen()->SetPageNumber( wxT( "1" ) );
m_schematic->Root().AddInstance( rootSheetPath );
m_schematic->Root().SetPageNumber( rootSheetPath, wxT( "1" ) );
rootSheetPath.SetPageNumber( wxT( "1" ) );
if( GetScreen() == nullptr )
{

View File

@ -90,4 +90,5 @@
//#define SEXPR_SCHEMATIC_FILE_VERSION 20220914 // Add support for DNP
//#define SEXPR_SCHEMATIC_FILE_VERSION 20220929 // Don't save property ID
//#define SEXPR_SCHEMATIC_FILE_VERSION 20221002 // Move instance data back into symbol definition.
#define SEXPR_SCHEMATIC_FILE_VERSION 20221004 // Move instance data back into symbol definition.
//#define SEXPR_SCHEMATIC_FILE_VERSION 20221004 // Move instance data back into symbol definition.
#define SEXPR_SCHEMATIC_FILE_VERSION 20221110 // Move sheet instance data to sheet definition.

View File

@ -246,9 +246,8 @@ SCH_SHEET* SCH_ALTIUM_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchem
SCH_SHEET_PATH sheetpath;
sheetpath.push_back( m_rootSheet );
m_rootSheet->AddInstance( sheetpath );
m_rootSheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a
// pageNumber record for it
// We'll update later if we find a pageNumber record for it.
sheetpath.SetPageNumber( "#" );
}
if( !m_rootSheet->GetScreen() )
@ -1775,8 +1774,7 @@ void SCH_ALTIUM_PLUGIN::ParseHarnessConnector( int aIndex, const std::map<wxStri
SCH_SHEET_PATH sheetpath = m_sheetPath;
sheetpath.push_back( sheet );
sheet->AddInstance( sheetpath );
sheet->SetPageNumber( sheetpath, "Harness #" );
sheetpath.SetPageNumber( "Harness #" );
m_harnessEntryParent = aIndex + m_harnessOwnerIndexOffset;
m_sheets.insert( { m_harnessEntryParent, sheet } );
@ -1946,8 +1944,6 @@ void SCH_ALTIUM_PLUGIN::ParseSheetSymbol( int aIndex,
SCH_SHEET_PATH sheetpath = m_sheetPath;
sheetpath.push_back( sheet );
sheet->AddInstance( sheetpath );
// We'll update later if we find a pageNumber record for it.
sheetpath.SetPageNumber( "#" );
@ -2891,7 +2887,7 @@ void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aPro
if( paramName == "SHEETNUMBER" )
{
m_rootSheet->SetPageNumber( m_sheetPath, elem.text );
m_sheetPath.SetPageNumber( elem.text );
}
else if( paramName == "TITLE" )
{

View File

@ -272,8 +272,7 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheets()
const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
SCH_SHEET_PATH rootPath;
rootPath.push_back( m_rootSheet );
m_rootSheet->AddInstance( rootPath );
m_rootSheet->SetPageNumber( rootPath, wxT( "1" ) );
rootPath.SetPageNumber( wxT( "1" ) );
if( orphanSheets.size() > 1 )
{
@ -2186,10 +2185,9 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadSheetAndChildSheets( LAYER_ID
sheet->GetScreen()->SetFileName( fn.GetFullPath() );
aParentSheet.Last()->GetScreen()->Append( sheet );
instance.push_back( sheet );
sheet->AddInstance( instance );
wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
sheet->SetPageNumber( instance, pageNumStr );
instance.SetPageNumber( pageNumStr );
sheet->AutoplaceFields( /* aScreen */ nullptr, /* aManual */ false );

View File

@ -709,7 +709,7 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
SCH_SHEET_PATH rootPath;
m_rootSheet->AddInstance( m_sheetPath );
m_rootSheet->SetPageNumber( m_sheetPath, wxT( "1" ) );
rootPath.SetPageNumber( wxT( "1" ) );
int sheetCount = countChildren( sheetNode->GetParent(), wxT( "sheet" ) );
@ -720,7 +720,6 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
x = 1;
y = 1;
// Loop through all the sheets
while( sheetNode )
{
VECTOR2I pos = VECTOR2I( x * schIUScale.MilsToIU( 1000 ),
@ -740,10 +739,7 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
m_sheetPath.push_back( sheet.get() );
loadSheet( sheetNode, i );
sheet->AddInstance( m_sheetPath );
m_sheetPath.SetPageNumber( pageNo );
m_rootSheet->AddInstance( m_sheetPath );
m_rootSheet->SetPageNumber( m_sheetPath, pageNo );
m_sheetPath.pop_back();
SCH_SCREEN* currentScreen = m_rootSheet->GetScreen();

View File

@ -2152,11 +2152,6 @@ void SCH_SEXPR_PARSER::parseSchSheetInstances( SCH_SHEET* aRootSheet, SCH_SCREEN
NeedSYMBOL();
instance.m_PageNumber = FromUTF8();
// Whitespaces are not permitted
for( wxString ch : whitespaces )
numReplacements += instance.m_PageNumber.Replace( ch, wxEmptyString );
// Empty page numbers are not permitted
if( instance.m_PageNumber.IsEmpty() )
{
@ -2164,6 +2159,13 @@ void SCH_SEXPR_PARSER::parseSchSheetInstances( SCH_SHEET* aRootSheet, SCH_SCREEN
instance.m_PageNumber = wxT( "#" );
numReplacements++;
}
else
{
// Whitespaces are not permitted
for( wxString ch : whitespaces )
numReplacements += instance.m_PageNumber.Replace( ch, wxEmptyString );
}
// Set the file as modified so the user can be warned.
if( numReplacements > 0 )
@ -2177,7 +2179,19 @@ void SCH_SEXPR_PARSER::parseSchSheetInstances( SCH_SHEET* aRootSheet, SCH_SCREEN
}
}
aScreen->m_sheetInstances.emplace_back( instance );
if( ( aScreen->GetFileFormatVersionAtLoad() >= 20221110 )
&& ( instance.m_Path.empty() ) )
{
SCH_SHEET_PATH rootSheetPath;
rootSheetPath.push_back( aRootSheet );
rootSheetPath.SetPageNumber( instance.m_PageNumber );
}
else
{
aScreen->m_sheetInstances.emplace_back( instance );
}
break;
}
@ -3088,8 +3102,90 @@ SCH_SHEET* SCH_SEXPR_PARSER::parseSheet()
sheet->AddPin( parseSchSheetPin( sheet.get() ) );
break;
case T_instances:
{
std::vector<SCH_SHEET_INSTANCE> instances;
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token != T_project )
Expecting( "project" );
NeedSYMBOL();
wxString projectName = FromUTF8();
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
if( token != T_path )
Expecting( "path" );
SCH_SHEET_INSTANCE instance;
instance.m_ProjectName = projectName;
NeedSYMBOL();
instance.m_Path = KIID_PATH( FromUTF8() );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_page:
{
NeedSYMBOL();
instance.m_PageNumber = FromUTF8();
// Empty page numbers are not permitted
if( instance.m_PageNumber.IsEmpty() )
{
// Use hash character instead
instance.m_PageNumber = wxT( "#" );
}
else
{
// Whitespaces are not permitted
std::vector<wxString> whitespaces = { wxT( "\r" ), wxT( "\n" ),
wxT( "\t" ), wxT( " " ) };
for( wxString ch : whitespaces )
instance.m_PageNumber.Replace( ch, wxEmptyString );
}
NeedRIGHT();
break;
}
default:
Expecting( "page" );
}
}
instances.emplace_back( instance );
}
}
sheet->SetInstances( instances );
break;
}
default:
Expecting( "at, size, stroke, background, uuid, property, or pin" );
Expecting( "at, size, stroke, background, instances, uuid, property, or pin" );
}
}

View File

@ -145,6 +145,7 @@ SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema
std::unique_ptr<SCH_SHEET> newSheet = std::make_unique<SCH_SHEET>( aSchematic );
wxFileName relPath( aFileName );
// Do not use wxPATH_UNIX as option in MakeRelativeTo(). It can create incorrect
// relative paths on Windows, because paths have a disk identifier (C:, D: ...)
relPath.MakeRelativeTo( aSchematic->Prj().GetProjectPath() );
@ -472,26 +473,10 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SHEET* aSheet )
}
}
// If this is the root sheet, save all of the sheet paths.
// If this is the root sheet, save the virtual root sheet instance information.
if( aSheet->IsRootSheet() )
{
SCH_SHEET_LIST sheetPaths( aSheet, true );
SCH_REFERENCE_LIST symbolInstances;
for( const SCH_SHEET_PATH& sheetPath : sheetPaths )
sheetPath.GetSymbols( symbolInstances, true, true );
symbolInstances.SortByReferenceOnly();
saveInstances( sheetPaths.GetSheetInstances(), 1 );
}
else
{
// Schematic files (SCH_SCREEN objects) can be shared so we have to save and restore
// symbol and sheet instance data even if the file being saved is not the root sheet
// because it is possible that the file is the root sheet of another project.
saveInstances( screen->m_sheetInstances, 1 );
saveInstances( aSheet->GetInstances(), 1 );
}
m_out->Print( 0, ")\n" );
@ -499,7 +484,7 @@ void SCH_SEXPR_PLUGIN::Format( SCH_SHEET* aSheet )
void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelectionPath,
const SCHEMATIC& aSchematic, OUTPUTFORMATTER* aFormatter,
SCHEMATIC& aSchematic, OUTPUTFORMATTER* aFormatter,
bool aForClipboard )
{
wxCHECK( aSelection && aSelectionPath && aFormatter, /* void */ );
@ -507,6 +492,7 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
LOCALE_IO toggle;
SCH_SHEET_LIST fullHierarchy = aSchematic.GetSheets();
m_schematic = &aSchematic;
m_out = aFormatter;
size_t i;
@ -642,8 +628,6 @@ void SCH_SEXPR_PLUGIN::Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelect
wxASSERT_MSG( symbolInstance.m_Path.MakeRelativeTo( selectionPath ),
"Symbol is not inside the selection path?" );
}
saveInstances( sheetinstances, 0 );
}
@ -690,8 +674,10 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
m_out->Print( 0, " (lib_id %s) (at %s %s %s)",
m_out->Quotew( aSymbol->GetLibId().Format().wx_str() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSymbol->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSymbol->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSymbol->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSymbol->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
bool mirrorX = aSymbol->GetOrientation() & SYM_MIRROR_X;
@ -833,7 +819,8 @@ void SCH_SEXPR_PLUGIN::saveSymbol( SCH_SYMBOL* aSymbol, const SCHEMATIC& aSchema
projectName = aSymbol->GetInstanceReferences()[i].m_ProjectName;
lastProjectUuid = aSymbol->GetInstanceReferences()[i].m_Path[0];
m_out->Print( aNestLevel + 2, "(project %s\n", m_out->Quotew( projectName ).c_str() );
m_out->Print( aNestLevel + 2, "(project %s\n",
m_out->Quotew( projectName ).c_str() );
project_open = true;
}
@ -884,8 +871,10 @@ void SCH_SEXPR_PLUGIN::saveField( SCH_FIELD* aField, int aNestLevel )
m_out->Print( aNestLevel, "(property %s %s (at %s %s %s)",
m_out->Quotew( fieldName ).c_str(),
m_out->Quotew( aField->GetText() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aField->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aField->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aField->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aField->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatAngle( aField->GetTextAngle() ).c_str() );
if( aField->IsNameShown() )
@ -917,8 +906,10 @@ void SCH_SEXPR_PLUGIN::saveBitmap( SCH_BITMAP* aBitmap, int aNestLevel )
wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
m_out->Print( aNestLevel, "(image (at %s %s)",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBitmap->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBitmap->GetPosition().y ).c_str() );
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBitmap->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBitmap->GetPosition().y ).c_str() );
if( aBitmap->GetImage()->GetScale() != 1.0 )
m_out->Print( 0, " (scale %g)", aBitmap->GetImage()->GetScale() );
@ -961,10 +952,14 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
wxCHECK_RET( aSheet != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(sheet (at %s %s) (size %s %s)",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSheet->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSheet->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSheet->GetSize().GetWidth() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aSheet->GetSize().GetHeight() ).c_str() );
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSheet->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSheet->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSheet->GetSize().GetWidth() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aSheet->GetSize().GetHeight() ).c_str() );
if( aSheet->GetFieldsAutoplaced() != FIELDS_AUTOPLACED_NO )
m_out->Print( 0, " (fields_autoplaced)" );
@ -999,8 +994,10 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
m_out->Print( aNestLevel + 1, "(pin %s %s (at %s %s %s)\n",
EscapedUTF8( pin->GetText() ).c_str(),
getSheetPinShapeToken( pin->GetShape() ),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pin->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pin->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
pin->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
pin->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatAngle( getSheetPinAngle( pin->GetSide() ) ).c_str() );
pin->Format( m_out, aNestLevel + 1, 0 );
@ -1010,6 +1007,67 @@ void SCH_SEXPR_PLUGIN::saveSheet( SCH_SHEET* aSheet, int aNestLevel )
m_out->Print( aNestLevel + 1, ")\n" ); // Closes pin token.
}
if( !aSheet->GetInstances().empty() )
{
m_out->Print( aNestLevel + 1, "(instances\n" );
KIID lastProjectUuid;
KIID rootSheetUuid = m_schematic->Root().m_Uuid;
SCH_SHEET_LIST fullHierarchy = m_schematic->GetSheets();
bool project_open = false;
for( size_t i = 0; i < aSheet->GetInstances().size(); i++ )
{
// If the instance data is part of this design but no longer has an associated sheet
// path, don't save it. This prevents large amounts of orphaned instance data for the
// current project from accumulating in the schematic files.
//
// Keep all instance data when copying to the clipboard. It may be needed on paste.
if( ( aSheet->GetInstances()[i].m_Path[0] == rootSheetUuid )
&& !fullHierarchy.GetSheetPathByKIIDPath( aSheet->GetInstances()[i].m_Path ) )
{
if( project_open && ( ( i + 1 == aSheet->GetInstances().size() )
|| lastProjectUuid != aSheet->GetInstances()[i+1].m_Path[0] ) )
{
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
project_open = false;
}
continue;
}
if( lastProjectUuid != aSheet->GetInstances()[i].m_Path[0] )
{
wxString projectName;
if( aSheet->GetInstances()[i].m_Path[0] == rootSheetUuid )
projectName = m_schematic->Prj().GetProjectName();
else
projectName = aSheet->GetInstances()[i].m_ProjectName;
lastProjectUuid = aSheet->GetInstances()[i].m_Path[0];
m_out->Print( aNestLevel + 2, "(project %s\n",
m_out->Quotew( projectName ).c_str() );
project_open = true;
}
wxString path = aSheet->GetInstances()[i].m_Path.AsString();
m_out->Print( aNestLevel + 3, "(path %s (page %s))\n",
m_out->Quotew( path ).c_str(),
m_out->Quotew( aSheet->GetInstances()[i].m_PageNumber ).c_str() );
if( project_open && ( ( i + 1 == aSheet->GetInstances().size() )
|| lastProjectUuid != aSheet->GetInstances()[i+1].m_Path[0] ) )
{
m_out->Print( aNestLevel + 2, ")\n" ); // Closes `project`.
project_open = false;
}
}
m_out->Print( aNestLevel + 1, ")\n" ); // Closes `instances`.
}
m_out->Print( aNestLevel, ")\n" ); // Closes sheet token.
}
@ -1019,9 +1077,12 @@ void SCH_SEXPR_PLUGIN::saveJunction( SCH_JUNCTION* aJunction, int aNestLevel )
wxCHECK_RET( aJunction != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(junction (at %s %s) (diameter %s) (color %d %d %d %s)\n",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aJunction->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aJunction->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aJunction->GetDiameter() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aJunction->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aJunction->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aJunction->GetDiameter() ).c_str(),
KiROUND( aJunction->GetColor().r * 255.0 ),
KiROUND( aJunction->GetColor().g * 255.0 ),
KiROUND( aJunction->GetColor().b * 255.0 ),
@ -1038,8 +1099,10 @@ void SCH_SEXPR_PLUGIN::saveNoConnect( SCH_NO_CONNECT* aNoConnect, int aNestLevel
wxCHECK_RET( aNoConnect != nullptr && m_out != nullptr, "" );
m_out->Print( aNestLevel, "(no_connect (at %s %s) (uuid %s))\n",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aNoConnect->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aNoConnect->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aNoConnect->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aNoConnect->GetPosition().y ).c_str(),
TO_UTF8( aNoConnect->m_Uuid.AsString() ) );
}
@ -1059,10 +1122,14 @@ void SCH_SEXPR_PLUGIN::saveBusEntry( SCH_BUS_ENTRY_BASE* aBusEntry, int aNestLev
else
{
m_out->Print( aNestLevel, "(bus_entry (at %s %s) (size %s %s)\n",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBusEntry->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBusEntry->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBusEntry->GetSize().GetWidth() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aBusEntry->GetSize().GetHeight() ).c_str() );
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBusEntry->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBusEntry->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBusEntry->GetSize().GetWidth() ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aBusEntry->GetSize().GetHeight() ).c_str() );
aBusEntry->GetStroke().Format( m_out, schIUScale, aNestLevel + 1 );
@ -1131,10 +1198,14 @@ void SCH_SEXPR_PLUGIN::saveLine( SCH_LINE* aLine, int aNestLevel )
m_out->Print( aNestLevel, "(%s (pts (xy %s %s) (xy %s %s))\n",
TO_UTF8( lineType ),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aLine->GetStartPoint().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aLine->GetStartPoint().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aLine->GetEndPoint().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aLine->GetEndPoint().y ).c_str() );
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aLine->GetStartPoint().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aLine->GetStartPoint().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aLine->GetEndPoint().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aLine->GetEndPoint().y ).c_str() );
line_stroke.Format( m_out, schIUScale, aNestLevel + 1 );
m_out->Print( 0, "\n" );
@ -1161,7 +1232,8 @@ void SCH_SEXPR_PLUGIN::saveText( SCH_TEXT* aText, int aNestLevel )
SCH_DIRECTIVE_LABEL* flag = static_cast<SCH_DIRECTIVE_LABEL*>( aText );
m_out->Print( 0, " (length %s)",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, flag->GetPinLength() ).c_str() );
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
flag->GetPinLength() ).c_str() );
}
EDA_ANGLE angle = aText->GetTextAngle();
@ -1190,16 +1262,20 @@ void SCH_SEXPR_PLUGIN::saveText( SCH_TEXT* aText, int aNestLevel )
if( aText->GetText().Length() < 50 )
{
m_out->Print( 0, " (at %s %s %s)",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aText->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aText->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aText->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aText->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
}
else
{
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel + 1, "(at %s %s %s)",
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aText->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aText->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aText->GetPosition().x ).c_str(),
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale,
aText->GetPosition().y ).c_str(),
EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
}

View File

@ -108,7 +108,7 @@ public:
void Format( SCH_SHEET* aSheet );
void Format( EE_SELECTION* aSelection, SCH_SHEET_PATH* aSelectionPath,
const SCHEMATIC& aSchematic, OUTPUTFORMATTER* aFormatter, bool aForClipboard );
SCHEMATIC& aSchematic, OUTPUTFORMATTER* aFormatter, bool aForClipboard );
void EnumerateSymbolLib( wxArrayString& aSymbolNameList,
const wxString& aLibraryPath,

View File

@ -1102,7 +1102,7 @@ void SCH_SHEET::Plot( PLOTTER* aPlotter, bool aBackground ) const
// Make the sheet object a clickable hyperlink (e.g. for PDF plotter)
std::vector<wxString> properties;
properties.emplace_back( EDA_TEXT::GotoPageHref( GetPageNumber( findSelf() ) ) );
properties.emplace_back( EDA_TEXT::GotoPageHref( getPageNumber( findSelf() ) ) );
for( const SCH_FIELD& field : GetFields() )
{
@ -1205,6 +1205,7 @@ bool SCH_SHEET::operator <( const SCH_ITEM& aItem ) const
bool SCH_SHEET::AddInstance( const SCH_SHEET_PATH& aSheetPath )
{
wxCHECK( aSheetPath.IsFullPath(), false );
wxCHECK( !aSheetPath.Last() || ( aSheetPath.Last()->m_Uuid != m_Uuid ), false );
for( const SCH_SHEET_INSTANCE& instance : m_instances )
{
@ -1227,9 +1228,10 @@ bool SCH_SHEET::AddInstance( const SCH_SHEET_PATH& aSheetPath )
}
wxString SCH_SHEET::GetPageNumber( const SCH_SHEET_PATH& aSheetPath ) const
wxString SCH_SHEET::getPageNumber( const SCH_SHEET_PATH& aSheetPath ) const
{
wxCHECK( aSheetPath.IsFullPath(), wxEmptyString );
wxCHECK( !aSheetPath.Last() || ( aSheetPath.Last()->m_Uuid != m_Uuid ), wxEmptyString );
wxString pageNumber;
KIID_PATH path = aSheetPath.Path();
@ -1247,9 +1249,10 @@ wxString SCH_SHEET::GetPageNumber( const SCH_SHEET_PATH& aSheetPath ) const
}
void SCH_SHEET::SetPageNumber( const SCH_SHEET_PATH& aSheetPath, const wxString& aPageNumber )
void SCH_SHEET::setPageNumber( const SCH_SHEET_PATH& aSheetPath, const wxString& aPageNumber )
{
wxCHECK( aSheetPath.IsFullPath(), /* void */ );
wxCHECK( !aSheetPath.Last() || ( aSheetPath.Last()->m_Uuid != m_Uuid ), /* void */ );
KIID_PATH path = aSheetPath.Path();

View File

@ -399,31 +399,6 @@ public:
*/
bool AddInstance( const SCH_SHEET_PATH& aInstance );
/**
* Return the sheet page number for \a aInstance.
*
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return an empty
* page number on release builds.
*
* @return the page number for the requested sheet instance.
*/
wxString GetPageNumber( const SCH_SHEET_PATH& aInstance ) const;
/**
* Set the page number for the sheet instance \a aInstance.
*
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return on release
* builds.
*
* @param[in] aInstance is the hierarchical path of the sheet.
* @param[in] aReference is the new page number for the sheet.
*/
void SetPageNumber( const SCH_SHEET_PATH& aInstance, const wxString& aPageNumber );
/**
* Compares page numbers of schematic sheets.
*
@ -438,6 +413,33 @@ public:
static const wxString GetDefaultFieldName( int aFieldNdx, bool aTranslated = true );
protected:
friend SCH_SHEET_PATH;
/**
* Return the sheet page number for \a aInstance.
*
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return an empty
* page number on release builds.
*
* @return the page number for the requested sheet instance.
*/
wxString getPageNumber( const SCH_SHEET_PATH& aInstance ) const;
/**
* Set the page number for the sheet instance \a aInstance.
*
* @warning The #SCH_SHEET_PATH object must be a full hierarchical path which means the
* #SCH_SHEET object at index 0 must be the root sheet. A partial sheet path
* will raise an assertion on debug builds and silently fail and return on release
* builds.
*
* @param[in] aInstance is the hierarchical path of the sheet.
* @param[in] aReference is the new page number for the sheet.
*/
void setPageNumber( const SCH_SHEET_PATH& aInstance, const wxString& aPageNumber );
/**
* Renumber the sheet pins in the sheet.
*

View File

@ -155,7 +155,8 @@ void SCH_SHEET_PATH::initFromOther( const SCH_SHEET_PATH& aOther )
bool SCH_SHEET_PATH::IsFullPath() const
{
return GetSheet( 0 ) && GetSheet( 0 )->IsRootSheet();
// The root sheet path is empty. All other sheet paths must start with the root sheet path.
return ( m_sheets.size() == 0 ) || ( GetSheet( 0 )->IsRootSheet() );
}
@ -192,7 +193,7 @@ int SCH_SHEET_PATH::Cmp( const SCH_SHEET_PATH& aSheetPathToTest ) const
int SCH_SHEET_PATH::ComparePageNum( const SCH_SHEET_PATH& aSheetPathToTest ) const
{
wxString pageA = GetPageNumber();
wxString pageA = this->GetPageNumber();
wxString pageB = aSheetPathToTest.GetPageNumber();
int pageNumComp = SCH_SHEET::ComparePageNum( pageA, pageB );
@ -507,7 +508,11 @@ wxString SCH_SHEET_PATH::GetPageNumber() const
wxCHECK( sheet, wxEmptyString );
return sheet->GetPageNumber( *this );
SCH_SHEET_PATH tmpPath = *this;
tmpPath.pop_back();
return sheet->getPageNumber( tmpPath );
}
@ -517,7 +522,12 @@ void SCH_SHEET_PATH::SetPageNumber( const wxString& aPageNumber )
wxCHECK( sheet, /* void */ );
sheet->SetPageNumber( *this, aPageNumber );
SCH_SHEET_PATH tmpPath = *this;
tmpPath.pop_back();
sheet->AddInstance( tmpPath );
sheet->setPageNumber( tmpPath, aPageNumber );
}
@ -612,7 +622,6 @@ int SCH_SHEET_PATH::AddNewSheetInstances( const SCH_SHEET_PATH& aPrefixSheetPath
// Prefix the new hierarchical path.
newSheetPath = newSheetPath + currentSheetPath;
newSheetPath.push_back( sheet );
wxString pageNumber;
@ -1119,7 +1128,7 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>& aSheetInstances )
{
for( const SCH_SHEET_PATH& path : *this )
for( SCH_SHEET_PATH& path : *this )
{
SCH_SHEET* sheet = path.Last();
@ -1141,8 +1150,7 @@ void SCH_SHEET_LIST::UpdateSheetInstances( const std::vector<SCH_SHEET_INSTANCE>
wxLogTrace( traceSchSheetPaths, "Setting sheet '%s' instance '%s' page number '%s'",
( sheet->GetName().IsEmpty() ) ? wxT( "root" ) : sheet->GetName(),
path.Path().AsString(), it->m_PageNumber );
sheet->AddInstance( path );
sheet->SetPageNumber( path, it->m_PageNumber );
path.SetPageNumber( it->m_PageNumber );
}
}
@ -1169,8 +1177,11 @@ std::vector<SCH_SHEET_INSTANCE> SCH_SHEET_LIST::GetSheetInstances() const
wxCHECK2( sheet, continue );
SCH_SHEET_INSTANCE instance;
instance.m_Path = path.Path();
instance.m_PageNumber = sheet->GetPageNumber( path );
SCH_SHEET_PATH tmpPath = path;
tmpPath.pop_back();
instance.m_Path = tmpPath.Path();
instance.m_PageNumber = path.GetPageNumber();
retval.push_back( instance );
}
@ -1183,11 +1194,7 @@ bool SCH_SHEET_LIST::AllSheetPageNumbersEmpty() const
{
for( const SCH_SHEET_PATH& instance : *this )
{
const SCH_SHEET* sheet = instance.Last();
wxCHECK2( sheet, continue );
if( !sheet->GetPageNumber( instance ).IsEmpty() )
if( !instance.GetPageNumber().IsEmpty() )
return false;
}
@ -1203,15 +1210,10 @@ void SCH_SHEET_LIST::SetInitialPageNumbers()
wxString tmp;
int pageNumber = 1;
for( const SCH_SHEET_PATH& instance : *this )
for( SCH_SHEET_PATH& instance : *this )
{
SCH_SHEET* sheet = instance.Last();
wxCHECK2( sheet, continue );
sheet->AddInstance( instance );
tmp.Printf( "%d", pageNumber );
sheet->SetPageNumber( instance, tmp );
instance.SetPageNumber( tmp );
pageNumber += 1;
}
}

View File

@ -69,6 +69,9 @@ struct SCH_SHEET_INSTANCE
KIID_PATH m_Path;
wxString m_PageNumber;
// The project name associated with this instance.
wxString m_ProjectName;
};
@ -176,6 +179,11 @@ public:
/// Forwarded method from std::vector
size_t size() const { return m_sheets.size(); }
std::vector<SCH_SHEET*>::iterator erase( std::vector<SCH_SHEET*>::const_iterator aPosition )
{
return m_sheets.erase( aPosition );
}
void Rehash();
size_t GetCurrentHash() const { return m_current_hash; }

View File

@ -146,6 +146,8 @@ public:
void RemoveInstance( const SCH_SHEET_PATH& aInstancePath );
void RemoveAllInstances() { m_instanceReferences.clear(); }
void SortInstances( bool ( *aSortFunction )( const SYMBOL_INSTANCE_REFERENCE& aLhs,
const SYMBOL_INSTANCE_REFERENCE& aRhs ) );

View File

@ -1829,8 +1829,7 @@ int SCH_DRAWING_TOOLS::DrawSheet( const TOOL_EVENT& aEvent )
{
SCH_SHEET_PATH sheetPath = instance;
sheetPath.push_back( sheet );
sheet->AddInstance( sheetPath );
sheet->SetPageNumber( sheetPath, wxString::Format( "%d", pageNum++ ) );
instance.SetPageNumber( wxString::Format( "%d", pageNum++ ) );
}
if( m_frame->EditSheetProperties( static_cast<SCH_SHEET*>( sheet ),

View File

@ -1691,8 +1691,6 @@ SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( const SCH_SHEET_PATH& aPas
SCH_SHEET_PATH sheetPath = aPastePath;
sheetPath.push_back( aSheet );
aSheet->AddInstance( sheetPath );
wxString pageNum;
if( m_clipboardSheetInstances.count( aClipPath ) > 0 )
@ -1700,7 +1698,7 @@ SCH_SHEET_PATH SCH_EDITOR_CONTROL::updatePastedSheet( const SCH_SHEET_PATH& aPas
else
pageNum = wxString::Format( "%d", static_cast<int>( aPastedSheetsSoFar->size() ) );
aSheet->SetPageNumber( sheetPath, pageNum );
sheetPath.SetPageNumber( pageNum );
aPastedSheetsSoFar->push_back( sheetPath );
if( aSheet->GetScreen() == nullptr )
@ -1793,7 +1791,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
}
catch( IO_ERROR& )
{
// If it wasn't content, then paste as content
// If it wasn't content, then paste as text object.
SCH_TEXT* text_item = new SCH_TEXT( wxPoint( 0, 0 ), content );
text_item->SetTextSpinStyle( TEXT_SPIN_STYLE::RIGHT ); // Left alignment
tempScreen->Append( text_item );
@ -1817,7 +1815,6 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
// SCH_SEXP_PLUGIN added the items to the paste screen, but not to the view or anything
// else. Pull them back out to start with.
//
EDA_ITEMS loadedItems;
bool sheetsPasted = false;
SCH_SHEET_LIST hierarchy = m_frame->Schematic().GetSheets();
@ -1849,8 +1846,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
std::map<KIID, EDA_ITEM*> itemMap;
hierarchy.FillItemMap( itemMap );
// Keep track of pasted sheets and symbols for the different
// paths to the hierarchy
// Keep track of pasted sheets and symbols for the different paths to the hierarchy.
std::map<SCH_SHEET_PATH, SCH_REFERENCE_LIST> pastedSymbols;
std::map<SCH_SHEET_PATH, SCH_SHEET_LIST> pastedSheets;
@ -1954,6 +1950,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
number = baseName.Last() + number;
baseName.RemoveLast();
}
// Update hierarchy to include any other sheets we already added, avoiding
// duplicate sheet names
hierarchy = m_frame->Schematic().GetSheets();
@ -2039,8 +2036,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
}
}
// Lines need both ends selected for a move after paste so the whole
// line moves
// Lines need both ends selected for a move after paste so the whole line moves.
if( item->Type() == SCH_LINE_T )
item->SetFlags( STARTPOINT | ENDPOINT );
@ -2049,6 +2045,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
// Reset flags for subsequent move operation
item->SetFlags( IS_NEW | IS_PASTED | IS_MOVING );
// Start out hidden so the pasted items aren't "ghosted" in their original location
// before being moved to the current location.
getView()->Hide( item, true );
@ -2129,9 +2126,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
m_frame->GetCurrentSheet().UpdateAllScreenReferences();
// Now clear the previous selection, select the pasted items, and fire up the "move"
// tool.
//
// Now clear the previous selection, select the pasted items, and fire up the "move" tool.
m_toolMgr->RunAction( EE_ACTIONS::clearSelection, true );
m_toolMgr->RunAction( EE_ACTIONS::addItemsToSel, true, &loadedItems );
@ -2156,7 +2151,6 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
};
// Prefer connection points (which should remain on grid)
for( EDA_ITEM* item : selection.Items() )
{
SCH_ITEM* sch_item = dynamic_cast<SCH_ITEM*>( item );
@ -2174,7 +2168,6 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
}
// Only process other points if we didn't find any connection points
if( closest_dist == INT_MAX )
{
for( EDA_ITEM* item : selection.Items() )