parent
0893e0043f
commit
2d48c81d58
|
@ -386,8 +386,14 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
|
|||
|
||||
bool SCH_EDIT_FRAME::AppendSchematic()
|
||||
{
|
||||
int i;
|
||||
wxString msg;
|
||||
wxString fullFileName;
|
||||
wxString topLevelSheetPath;
|
||||
wxFileName tmp;
|
||||
SCH_SCREEN* screen = GetScreen();
|
||||
bool libTableChanged = false;
|
||||
|
||||
|
||||
if( !screen )
|
||||
{
|
||||
|
@ -406,10 +412,414 @@ bool SCH_EDIT_FRAME::AppendSchematic()
|
|||
|
||||
fullFileName = dlg.GetPath();
|
||||
|
||||
if( !LoadSheetFromFile( GetCurrentSheet().Last(), &GetCurrentSheet(), fullFileName ) )
|
||||
wxFileName fn = fullFileName;
|
||||
|
||||
if( fn.IsRelative() )
|
||||
{
|
||||
fn.MakeAbsolute();
|
||||
fullFileName = fn.GetFullPath();
|
||||
}
|
||||
|
||||
// Load the schematic into a temporary sheet.
|
||||
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
|
||||
std::unique_ptr< SCH_SHEET> newSheet( new SCH_SHEET );
|
||||
|
||||
newSheet->SetFileName( fullFileName );
|
||||
|
||||
try
|
||||
{
|
||||
pi->Load( fullFileName, &Kiway(), newSheet.get() );
|
||||
|
||||
if( !pi->GetError().IsEmpty() )
|
||||
{
|
||||
DisplayErrorMessage( this,
|
||||
_( "The entire schematic could not be loaded. Errors "
|
||||
"occurred attempting to load hierarchical sheet "
|
||||
"schematics." ),
|
||||
pi->GetError() );
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error occurred loading schematic file \"%s\"." ), fullFileName );
|
||||
DisplayErrorMessage( this, msg, ioe.What() );
|
||||
|
||||
msg.Printf( _( "Failed to load schematic \"%s\"" ), fullFileName );
|
||||
AppendMsgPanel( wxEmptyString, msg, CYAN );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = fn;
|
||||
|
||||
// If the appended schematic is in a different folder from the current project and
|
||||
// it contains hierarchical sheets, the hierarchical sheet paths need to be updated.
|
||||
if( fn.GetPath( wxPATH_GET_SEPARATOR ) != Prj().GetProjectPath() && newSheet->CountSheets() )
|
||||
{
|
||||
// Give the user the option to choose relative path if possible.
|
||||
if( tmp.MakeRelativeTo( Prj().GetProjectPath() ) )
|
||||
{
|
||||
wxMessageDialog msgDlg1(
|
||||
this,
|
||||
"Do you want to use a relative path to the appended "
|
||||
"schematic?", "Select Path Type",
|
||||
wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
|
||||
msgDlg1.SetYesNoLabels( wxMessageDialog::ButtonLabel( "Use Relative Path" ),
|
||||
wxMessageDialog::ButtonLabel( "Use Absolute Path" ) );
|
||||
int rsp = msgDlg1.ShowModal();
|
||||
|
||||
if( rsp == wxID_CANCEL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if( rsp == wxID_NO )
|
||||
{
|
||||
topLevelSheetPath = fn.GetPathWithSep();
|
||||
|
||||
if( wxFileName::GetPathSeparator() == '\\' )
|
||||
topLevelSheetPath.Replace( "\\", "/" );
|
||||
}
|
||||
else
|
||||
{
|
||||
topLevelSheetPath = tmp.GetPathWithSep( wxPATH_UNIX );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
topLevelSheetPath = tmp.GetPathWithSep();
|
||||
|
||||
if( wxFileName::GetPathSeparator() == '\\' )
|
||||
topLevelSheetPath.Replace( "\\", "/" );
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure any new sheet changes do not cause any recursion issues.
|
||||
SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the schematic sheet hierarchy.
|
||||
SCH_SHEET_LIST sheetHierarchy( newSheet.get() ); // This is the hierarchy of the import.
|
||||
|
||||
wxFileName destFile = screen->GetFileName();
|
||||
|
||||
if( destFile.IsRelative() )
|
||||
destFile.MakeAbsolute( Prj().GetProjectPath() );
|
||||
|
||||
if( hierarchy.TestForRecursion( sheetHierarchy, destFile.GetFullPath( wxPATH_UNIX ) ) )
|
||||
{
|
||||
msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
|
||||
"has the sheet \"%s\" or one of it's subsheets as a parent somewhere in "
|
||||
"the schematic hierarchy." ),
|
||||
destFile.GetFullPath() );
|
||||
DisplayError( this, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxArrayString names;
|
||||
|
||||
// Make sure the imported schematic has been remapped to the symbol library table.
|
||||
SCH_SCREENS newScreens( newSheet.get() ); // All screens associated with the import.
|
||||
|
||||
if( newScreens.HasNoFullyDefinedLibIds() )
|
||||
{
|
||||
DisplayInfoMessage( this,
|
||||
"This schematic has not been remapped to the symbol library\n"
|
||||
"table. The project this schematic belongs to must first be\n"
|
||||
"remapped before it can be imported into the current project." );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxArrayString newLibNames;
|
||||
SCH_SCREENS prjScreens( g_RootSheet );
|
||||
|
||||
newScreens.GetLibNicknames( names );
|
||||
|
||||
wxMessageDialog::ButtonLabel okButtonLabel( _( "Continue Append" ) );
|
||||
wxMessageDialog::ButtonLabel cancelButtonLabel( _( "Cancel Append" ) );
|
||||
|
||||
if( fn.GetPath( wxPATH_GET_SEPARATOR ) == Prj().GetProjectPath()
|
||||
&& !prjScreens.HasSchematic( fullFileName ) )
|
||||
{
|
||||
// A schematic in the current project path that isn't part of the current project.
|
||||
// It's possible the user copied this schematic from another project so the library
|
||||
// links may not be avaible. Even this is check is no guarantee that all symbol
|
||||
// library links are valid but it's better than nothing.
|
||||
for( const auto& name : names )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
}
|
||||
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
msg = _( "There are library names in the appended schematic that are missing "
|
||||
"from the project library table. This may result in broken symbol "
|
||||
"library links for the appended schematic. Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg1( this, msg, _( "Continue Append Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg1.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg1.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( fn.GetPath( wxPATH_GET_SEPARATOR ) != Prj().GetProjectPath() )
|
||||
{
|
||||
// A schematic loaded from a path other than the current project path.
|
||||
|
||||
// If there are symbol libraries in the imported schematic that are not in the
|
||||
// symbol library table of this project, there could be a lot of broken symbol
|
||||
// library links. Attempt to add the missing libraries to the project symbol
|
||||
// library table.
|
||||
wxArrayString duplicateLibNames;
|
||||
|
||||
for( const auto& name : names )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
else
|
||||
duplicateLibNames.Add( name );
|
||||
}
|
||||
|
||||
SYMBOL_LIB_TABLE table;
|
||||
wxFileName symLibTableFn( fn.GetPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// If there are any new or duplicate libraries, check to see if it's possible that
|
||||
// there could be any missing libraries that would cause broken symbol library links.
|
||||
if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
|
||||
{
|
||||
if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
|
||||
{
|
||||
msg.Printf( _( "The project library table \"%s\" does not exist or cannot "
|
||||
"be read. This may result in broken symbol links for the "
|
||||
"appended schematic. Do you wish to continue?" ),
|
||||
fn.GetFullPath() );
|
||||
wxMessageDialog msgDlg2( this, msg, _( "Continue Append Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg2.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg2.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
table.Load( symLibTableFn.GetFullPath() );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "An error occurred loading the symbol library table \"%s\"." ),
|
||||
symLibTableFn.GetFullPath() );
|
||||
DisplayErrorMessage( NULL, msg, ioe.What() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if any of the symbol libraries found in the appended schematic do
|
||||
// not exist in the current project are missing from the appended project symbol
|
||||
// library table.
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
bool missingLibNames = table.IsEmpty();
|
||||
|
||||
if( !missingLibNames )
|
||||
{
|
||||
for( const auto& newLibName : newLibNames )
|
||||
{
|
||||
if( !table.HasLibrary( newLibName ) )
|
||||
{
|
||||
missingLibNames = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( missingLibNames )
|
||||
{
|
||||
msg = _( "There are library names in the appended schematic that are missing "
|
||||
"from the appended schematic project library table. This may result "
|
||||
"in broken symbol library links for the appended schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg3( this, msg, _( "Continue Append Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg3.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The library name already exists in the current project. Check to see if the
|
||||
// duplicate name is the same library in the current project. If it's not, it's
|
||||
// most likely that the symbol library links will be broken.
|
||||
if( !duplicateLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
bool libNameConflict = false;
|
||||
|
||||
for( const auto& duplicateLibName : duplicateLibNames )
|
||||
{
|
||||
const SYMBOL_LIB_TABLE_ROW* thisRow = nullptr;
|
||||
const SYMBOL_LIB_TABLE_ROW* otherRow = nullptr;
|
||||
|
||||
if( Prj().SchSymbolLibTable()->HasLibrary( duplicateLibName ) )
|
||||
thisRow = Prj().SchSymbolLibTable()->FindRow( duplicateLibName );
|
||||
|
||||
if( table.HasLibrary( duplicateLibName ) )
|
||||
otherRow = table.FindRow( duplicateLibName );
|
||||
|
||||
// It's in the global library table so there is no conflict.
|
||||
if( thisRow && !otherRow )
|
||||
continue;
|
||||
|
||||
if( !thisRow || !otherRow )
|
||||
continue;
|
||||
|
||||
wxFileName otherUriFileName;
|
||||
wxString thisURI = thisRow->GetFullURI( true );
|
||||
wxString otherURI = otherRow->GetFullURI( false);
|
||||
|
||||
if( otherURI.Contains( "${KIPRJMOD}" ) || otherURI.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
otherUriFileName.SetPath( fn.GetPath() );
|
||||
otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
|
||||
otherURI = otherUriFileName.GetFullPath();
|
||||
}
|
||||
|
||||
if( thisURI != otherURI )
|
||||
{
|
||||
libNameConflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( libNameConflict )
|
||||
{
|
||||
msg = _( "A duplicate library name that references a different library exists "
|
||||
"in the current library table. This conflict cannot be resolved and "
|
||||
"may result in broken symbol library links for the appended schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg4( this, msg, _( "Continue Append Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg4.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All (most?) of the possible broken symbol library link cases are covered. Map the
|
||||
// new appended schematic project symbol library table entries to the current project
|
||||
// symbol library table.
|
||||
if( !newLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
for( const auto& libName : newLibNames )
|
||||
{
|
||||
if( !table.HasLibrary( libName )
|
||||
|| Prj().SchSymbolLibTable()->HasLibrary( libName ) )
|
||||
continue;
|
||||
|
||||
// Don't expand environment variable because KIPRJMOD will not be correct
|
||||
// for a different project.
|
||||
wxString uri = table.GetFullURI( libName, false );
|
||||
wxFileName newLib;
|
||||
|
||||
if( uri.Contains( "${KIPRJMOD}" ) || uri.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
newLib.SetPath( fn.GetPath() );
|
||||
newLib.SetFullName( uri.AfterLast( '}' ) );
|
||||
uri = newLib.GetFullPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = table.GetFullURI( libName );
|
||||
}
|
||||
|
||||
// Add the library from the imported project to the current project
|
||||
// symbol library table.
|
||||
const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
|
||||
|
||||
auto newRow = new SYMBOL_LIB_TABLE_ROW( libName, uri, row->GetType(),
|
||||
row->GetOptions(), row->GetDescr() );
|
||||
|
||||
Prj().SchSymbolLibTable()->InsertRow( newRow );
|
||||
libTableChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newScreens.ClearAnnotation();
|
||||
|
||||
// Check for duplicate sheet names in the current page.
|
||||
wxArrayString duplicateSheetNames;
|
||||
SCH_TYPE_COLLECTOR sheets;
|
||||
|
||||
sheets.Collect( screen->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
|
||||
|
||||
for( i = 0; i < sheets.GetCount(); ++i )
|
||||
{
|
||||
if( newSheet->GetScreen()->GetSheet( ( ( SCH_SHEET* ) sheets[i] )->GetName() ) )
|
||||
duplicateSheetNames.Add( ( ( SCH_SHEET* ) sheets[i] )->GetName() );
|
||||
}
|
||||
|
||||
if( !duplicateSheetNames.IsEmpty() )
|
||||
{
|
||||
msg.Printf( "Duplicate sheet names exist on the current page. Do you want to "
|
||||
"automatically rename the duplicate sheet names?" );
|
||||
|
||||
if( !IsOK( this, msg ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
SCH_SCREEN* newScreen = newSheet->GetScreen();
|
||||
wxCHECK_MSG( newScreen, false, "No screen defined for imported sheet." );
|
||||
|
||||
for( const auto& duplicateName : duplicateSheetNames )
|
||||
{
|
||||
SCH_SHEET* renamedSheet = newScreen->GetSheet( duplicateName );
|
||||
|
||||
wxCHECK2_MSG( renamedSheet, continue,
|
||||
"Sheet " + duplicateName + " not found in imported schematic." );
|
||||
|
||||
timestamp_t newtimestamp = GetNewTimeStamp();
|
||||
renamedSheet->SetTimeStamp( newtimestamp );
|
||||
renamedSheet->SetName( wxString::Format( "Sheet%8.8lX", (unsigned long) newtimestamp ) );
|
||||
}
|
||||
|
||||
SCH_TYPE_COLLECTOR newTopLevelSheets;
|
||||
|
||||
newTopLevelSheets.Collect( newSheet->GetScreen()->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
|
||||
|
||||
for( i = 0; i < newTopLevelSheets.GetCount(); ++i )
|
||||
{
|
||||
SCH_SHEET* tmpSheet = dynamic_cast< SCH_SHEET* >( newTopLevelSheets[i] );
|
||||
wxCHECK2( tmpSheet != nullptr, continue );
|
||||
tmpSheet->SetFileName( topLevelSheetPath + tmpSheet->GetFileName() );
|
||||
}
|
||||
|
||||
if( libTableChanged )
|
||||
Prj().SchSymbolLibTable()->Save( Prj().GetProjectPath() +
|
||||
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// It is finally safe to add the imported schematic.
|
||||
screen->Append( newScreen );
|
||||
|
||||
SCH_SCREENS allScreens;
|
||||
allScreens.ReplaceDuplicateTimeStamps();
|
||||
|
||||
SCH_SCREENS screens( GetCurrentSheet().Last() );
|
||||
screens.UpdateSymbolLinks( true );
|
||||
|
||||
// Clear all annotation in the imported schematic to prevent clashes with existing annotation.
|
||||
// Must be done after updating the symbol links as we need to know about multi-unit parts.
|
||||
// screens.ClearAnnotation();
|
||||
|
||||
screens.TestDanglingEnds();
|
||||
|
||||
GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId );
|
||||
|
|
|
@ -703,9 +703,33 @@ public:
|
|||
bool OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl = 0 ) override;
|
||||
|
||||
/**
|
||||
* Import a KiCad schematic into the current sheet.
|
||||
* Import a KiCad schematic into the current page.
|
||||
*
|
||||
* @return True if the schematic was imported properly.
|
||||
* In order to import a schematic a lot of things have to happen to before the contents
|
||||
* of the imported schematic can be appended to the current page. The following list
|
||||
* describes this process:
|
||||
*
|
||||
* - Load the schematic into a temporary SCH_SHEET object.
|
||||
* - Make sure the imported schematic does not cause any hierarchy recursion issues.
|
||||
* - Verify the imported schematic uses fully qualified #LIB_ID objects (symbol library table).
|
||||
* - Check to see if any symbol libraries need to be added to the current project's symbol
|
||||
* library table. This includes:
|
||||
* - Check if the symbol library already exists in the project or global symbol library
|
||||
* table.
|
||||
* - Convert symbol library URLS that use the ${KIPRJMOD} environment variable to absolute
|
||||
* paths. ${KIPRJMOD} will not be the same for this project.
|
||||
* - Check for duplicate symbol library nicknames and change the new symbol library nickname
|
||||
* to prevent library name clashes.
|
||||
* - Update all schematic symbol LIB_ID object library nicknames when the library nickname
|
||||
* was changed to prevent clashes.
|
||||
* - Check for duplicate sheet names which is illegal and automatically rename any duplicate
|
||||
* sheets in the imported schematic.
|
||||
* - Clear all of the annotation in the imported schematic to prevent clashes.
|
||||
* - Append the objects from the temporary sheet to the current page.
|
||||
* - Replace any duplicate time stamps.
|
||||
* - Refresh the symbol library links.
|
||||
*
|
||||
* @return True if the project was imported properly.
|
||||
*/
|
||||
bool AppendSchematic();
|
||||
|
||||
|
@ -956,35 +980,6 @@ private:
|
|||
void EditSchematicText( SCH_TEXT* TextStruct );
|
||||
void ChangeTextOrient( SCH_TEXT* aTextItem );
|
||||
|
||||
/**
|
||||
* Verify that \a aSheet will not cause a recursion error in \a aHierarchy.
|
||||
*
|
||||
* @param aSheet is the #SCH_SHEET object to test.
|
||||
* @param aHierarchy is the #SCH_SHEET_PATH where \a aSheet is going to reside.
|
||||
*
|
||||
* @return true if \a aSheet will cause a resursion error in \a aHierarchy.
|
||||
*/
|
||||
bool checkSheetForRecursion( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy );
|
||||
|
||||
/**
|
||||
* Verify that the symbol library links \a aSheet and all of it's child sheets have
|
||||
* been remapped to the symbol library table.
|
||||
*
|
||||
* @param aSheet is the #SCH_SHEET object to test.
|
||||
*
|
||||
* @return true if \a aSheet and it's child sheets have not been remapped.
|
||||
*/
|
||||
bool checkForNoFullyDefinedLibIds( SCH_SHEET* aSheet );
|
||||
|
||||
/**
|
||||
* Load the given filename but sets the path to the current project path.
|
||||
*
|
||||
* @param full filepath of file to be imported.
|
||||
* @param aFileType SCH_FILE_T value for file type
|
||||
*/
|
||||
bool importFile( const wxString& aFileName, int aFileType );
|
||||
|
||||
public:
|
||||
/**
|
||||
* Command event handler to change a text type to another one.
|
||||
*
|
||||
|
@ -1107,54 +1102,15 @@ public:
|
|||
wxPoint GetLastSheetPinPosition() const { return m_lastSheetPinPosition; }
|
||||
|
||||
private:
|
||||
void InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename );
|
||||
|
||||
/**
|
||||
* Load a the KiCad schematic file \a aFileName into the sheet \a aSheet.
|
||||
* Load the given filename but sets the path to the current project path.
|
||||
*
|
||||
* If \a aSheet does not have a valid #SCH_SCREEN object, the schematic is loaded into
|
||||
* \a Sheet. Otherwise, it is appended to the current #SCH_SCREEN object.
|
||||
*
|
||||
* In order to import a schematic a lot of things have to happen to before the contents
|
||||
* of the imported schematic can be appended to the current page. The following list
|
||||
* describes this process:
|
||||
*
|
||||
* - Load the schematic into a temporary #SCH_SHEET object.
|
||||
* - Make sure the imported schematic does not cause any hierarchy recursion issues.
|
||||
* - Verify the imported schematic uses fully qualified #LIB_ID objects (symbol library table).
|
||||
* - Check all of the possible combinations that could cause broken symbol library links
|
||||
* and give the user the option to cancel the append process. The following conditions
|
||||
* are check but they still do not guarantee that there will not be any broken symbol
|
||||
* library links:
|
||||
* - The source schematic is in the current project path and contains symbol library
|
||||
* nicknames not found in the project symbol library table. This can happen if the
|
||||
* schematic is copied to the current project path from another project.
|
||||
* - The source schematic is in a different path and there are symbol library link nicknames
|
||||
* that do not exist in either the current symbol library table or the source project
|
||||
* symbol library table if it exists in the source path.
|
||||
* - The source schematic is in a different path and contains duplicate symbol library
|
||||
* nicknames that point to different libraries.
|
||||
* - Check to see if any symbol libraries need to be added to the current project's symbol
|
||||
* library table. This includes:
|
||||
* - Check if the symbol library already exists in the project or global symbol library
|
||||
* table.
|
||||
* - Convert symbol library URLS that use the ${KIPRJMOD} environment variable to absolute
|
||||
* paths. ${KIPRJMOD} will not be the same for this project.
|
||||
* - Clear all of the annotation in the imported schematic to prevent clashes.
|
||||
* - Append the objects from the temporary sheet to the current page.
|
||||
* - Replace any duplicate time stamps.
|
||||
* - Refresh the symbol library links.
|
||||
*
|
||||
* @param aSheet is the sheet to either append or load the schematic.
|
||||
* @param aHierarchy is the current position in the schematic hierarchy used to test for
|
||||
* possible file recursion issues.
|
||||
* @param aFileName is the file name to load. The file name is expected to have an absolute
|
||||
* path.
|
||||
*
|
||||
* @return True if the schematic was imported properly.
|
||||
* @param full filepath of file to be imported.
|
||||
* @param aFileType SCH_FILE_T value for file type
|
||||
*/
|
||||
bool LoadSheetFromFile( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
||||
const wxString& aFileName );
|
||||
bool importFile( const wxString& aFileName, int aFileType );
|
||||
|
||||
bool validateSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy );
|
||||
|
||||
/**
|
||||
* Create a new SCH_SHEET_PIN object and add it to \a aSheet at the current cursor position.
|
||||
|
@ -1254,6 +1210,7 @@ public:
|
|||
*/
|
||||
void OrientComponent( COMPONENT_ORIENTATION_T aOrientation = CMP_NORMAL );
|
||||
|
||||
private:
|
||||
void OnSelectUnit( wxCommandEvent& aEvent );
|
||||
void ConvertPart( SCH_COMPONENT* DrawComponent );
|
||||
|
||||
|
@ -1272,6 +1229,7 @@ public:
|
|||
void PasteListOfItems( wxDC* DC );
|
||||
|
||||
/* Undo - redo */
|
||||
public:
|
||||
|
||||
/**
|
||||
* Create a copy of the current schematic item, and put it in the undo list.
|
||||
|
|
|
@ -38,487 +38,8 @@
|
|||
#include <sch_sheet.h>
|
||||
#include <sch_sheet_path.h>
|
||||
#include <sch_view.h>
|
||||
#include <symbol_lib_table.h>
|
||||
|
||||
#include <dialogs/dialog_sch_sheet_props.h>
|
||||
#include <dialogs/dialog_sch_edit_sheet_pin.h>
|
||||
#include <tool/actions.h>
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::checkSheetForRecursion( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy )
|
||||
{
|
||||
wxASSERT( aSheet && aHierarchy );
|
||||
|
||||
wxString msg;
|
||||
SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the full schematic sheet hierarchy.
|
||||
SCH_SHEET_LIST sheetHierarchy( aSheet ); // This is the hierarchy of the loaded file.
|
||||
|
||||
wxFileName destFile = aHierarchy->LastScreen()->GetFileName();
|
||||
|
||||
// SCH_SCREEN object file paths are expected to be absolute. If this assert fires,
|
||||
// something is seriously broken.
|
||||
wxASSERT( destFile.IsAbsolute() );
|
||||
|
||||
if( hierarchy.TestForRecursion( sheetHierarchy, destFile.GetFullPath( wxPATH_UNIX ) ) )
|
||||
{
|
||||
msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
|
||||
"has the sheet \"%s\" or one of it's subsheets as a parent somewhere in "
|
||||
"the schematic hierarchy." ),
|
||||
destFile.GetFullPath() );
|
||||
DisplayError( this, msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::checkForNoFullyDefinedLibIds( SCH_SHEET* aSheet )
|
||||
{
|
||||
wxASSERT( aSheet && aSheet->GetScreen() );
|
||||
|
||||
wxString msg;
|
||||
SCH_SCREENS newScreens( aSheet );
|
||||
|
||||
if( newScreens.HasNoFullyDefinedLibIds() )
|
||||
{
|
||||
msg.Printf( _( "The schematic \"%s\" has not had it's symbol library links remapped "
|
||||
"to the symbol library table. The project this schematic belongs to "
|
||||
"must first be remapped before it can be imported into the current "
|
||||
"project." ), aSheet->GetScreen()->GetFileName() );
|
||||
DisplayInfoMessage( this, msg );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void SCH_EDIT_FRAME::InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename )
|
||||
{
|
||||
aSheet->SetScreen( new SCH_SCREEN( &Kiway() ) );
|
||||
aSheet->GetScreen()->SetModify();
|
||||
aSheet->GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax );
|
||||
aSheet->GetScreen()->SetFileName( aNewFilename );
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::LoadSheetFromFile( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
||||
const wxString& aFileName )
|
||||
{
|
||||
wxASSERT( aSheet && aHierarchy );
|
||||
|
||||
int i;
|
||||
wxString msg;
|
||||
wxString topLevelSheetPath;
|
||||
wxFileName tmp;
|
||||
wxFileName currentSheetFileName;
|
||||
bool libTableChanged = false;
|
||||
SCH_SCREEN* currentScreen = aHierarchy->LastScreen();
|
||||
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
|
||||
std::unique_ptr< SCH_SHEET> newSheet( new SCH_SHEET );
|
||||
|
||||
wxFileName fileName( aFileName );
|
||||
|
||||
if( !fileName.IsAbsolute() )
|
||||
{
|
||||
wxCHECK_MSG( fileName.MakeAbsolute(), false,
|
||||
wxString::Format( "Cannot make file name \"%s\" path absolute.",
|
||||
aFileName ) );
|
||||
}
|
||||
|
||||
wxString fullFilename = fileName.GetFullPath();
|
||||
|
||||
try
|
||||
{
|
||||
if( aSheet->GetScreen() != nullptr )
|
||||
{
|
||||
newSheet.reset( pi->Load( fullFilename, &Kiway() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
newSheet->SetFileName( fullFilename );
|
||||
pi->Load( fullFilename, &Kiway(), newSheet.get() );
|
||||
}
|
||||
|
||||
if( !pi->GetError().IsEmpty() )
|
||||
{
|
||||
msg = _( "The entire schematic could not be loaded. Errors occurred attempting "
|
||||
"to load hierarchical sheet schematics." );
|
||||
|
||||
wxMessageDialog msgDlg1( this, msg, _( "Schematic Load Error" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg1.SetOKLabel( wxMessageDialog::ButtonLabel( _( "Use partial schematic" ) ) );
|
||||
msgDlg1.SetExtendedMessage( pi->GetError() );
|
||||
|
||||
if( msgDlg1.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error occurred loading schematic file \"%s\"." ), fullFilename );
|
||||
DisplayErrorMessage( this, msg, ioe.What() );
|
||||
|
||||
msg.Printf( _( "Failed to load schematic \"%s\"" ), fullFilename );
|
||||
AppendMsgPanel( wxEmptyString, msg, CYAN );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
tmp = fileName;
|
||||
|
||||
// If the loaded schematic is in a different folder from the current project and
|
||||
// it contains hierarchical sheets, the hierarchical sheet paths need to be updated.
|
||||
if( fileName.GetPath( wxPATH_GET_SEPARATOR ) != Prj().GetProjectPath()
|
||||
&& newSheet->CountSheets() )
|
||||
{
|
||||
// Give the user the option to choose relative path if possible.
|
||||
if( tmp.MakeRelativeTo( Prj().GetProjectPath() ) )
|
||||
{
|
||||
wxMessageDialog msgDlg2(
|
||||
this,
|
||||
"Do you want to use a relative path to the loaded "
|
||||
"schematic?", "Select Path Type",
|
||||
wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
|
||||
msgDlg2.SetYesNoLabels( wxMessageDialog::ButtonLabel( "Use Relative Path" ),
|
||||
wxMessageDialog::ButtonLabel( "Use Absolute Path" ) );
|
||||
int rsp = msgDlg2.ShowModal();
|
||||
|
||||
if( rsp == wxID_CANCEL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if( rsp == wxID_NO )
|
||||
{
|
||||
topLevelSheetPath = fileName.GetPathWithSep();
|
||||
|
||||
if( wxFileName::GetPathSeparator() == '\\' )
|
||||
topLevelSheetPath.Replace( "\\", "/" );
|
||||
}
|
||||
else
|
||||
{
|
||||
topLevelSheetPath = tmp.GetPathWithSep( wxPATH_UNIX );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
topLevelSheetPath = tmp.GetPathWithSep();
|
||||
|
||||
if( wxFileName::GetPathSeparator() == '\\' )
|
||||
topLevelSheetPath.Replace( "\\", "/" );
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure any new sheet changes do not cause any recursion issues.
|
||||
SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the schematic sheet hierarchy.
|
||||
SCH_SHEET_LIST sheetHierarchy( newSheet.get() ); // This is the hierarchy of the loaded file.
|
||||
|
||||
if( checkSheetForRecursion( newSheet.get(), aHierarchy )
|
||||
|| checkForNoFullyDefinedLibIds( newSheet.get() ) )
|
||||
return false;
|
||||
|
||||
// Make a valiant attempt to warn the user of all possible scenarios where there could
|
||||
// be broken symbol library links.
|
||||
wxArrayString names;
|
||||
wxArrayString newLibNames;
|
||||
SCH_SCREENS newScreens( newSheet.get() ); // All screens associated with the import.
|
||||
SCH_SCREENS prjScreens( g_RootSheet );
|
||||
|
||||
newScreens.GetLibNicknames( names );
|
||||
|
||||
wxMessageDialog::ButtonLabel okButtonLabel( _( "Continue Load" ) );
|
||||
wxMessageDialog::ButtonLabel cancelButtonLabel( _( "Cancel Load" ) );
|
||||
|
||||
if( fileName.GetPath( wxPATH_GET_SEPARATOR ) == Prj().GetProjectPath()
|
||||
&& !prjScreens.HasSchematic( fullFilename ) )
|
||||
{
|
||||
// A schematic in the current project path that isn't part of the current project.
|
||||
// It's possible the user copied this schematic from another project so the library
|
||||
// links may not be avaible. Even this is check is no guarantee that all symbol
|
||||
// library links are valid but it's better than nothing.
|
||||
for( const auto& name : names )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
}
|
||||
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
msg = _( "There are library names in the loaded schematic that are missing "
|
||||
"from the project library table. This may result in broken symbol "
|
||||
"library links for the loaded schematic. Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg3( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg3.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( fileName.GetPath( wxPATH_GET_SEPARATOR ) != Prj().GetProjectPath() )
|
||||
{
|
||||
// A schematic loaded from a path other than the current project path.
|
||||
|
||||
// If there are symbol libraries in the imported schematic that are not in the
|
||||
// symbol library table of this project, there could be a lot of broken symbol
|
||||
// library links. Attempt to add the missing libraries to the project symbol
|
||||
// library table.
|
||||
wxArrayString duplicateLibNames;
|
||||
|
||||
for( const auto& name : names )
|
||||
{
|
||||
if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
|
||||
newLibNames.Add( name );
|
||||
else
|
||||
duplicateLibNames.Add( name );
|
||||
}
|
||||
|
||||
SYMBOL_LIB_TABLE table;
|
||||
wxFileName symLibTableFn( fileName.GetPath(),
|
||||
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// If there are any new or duplicate libraries, check to see if it's possible that
|
||||
// there could be any missing libraries that would cause broken symbol library links.
|
||||
if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
|
||||
{
|
||||
if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
|
||||
{
|
||||
msg.Printf( _( "The project library table \"%s\" does not exist or cannot "
|
||||
"be read. This may result in broken symbol links for the "
|
||||
"schematic. Do you wish to continue?" ),
|
||||
fileName.GetFullPath() );
|
||||
wxMessageDialog msgDlg4( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg4.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
table.Load( symLibTableFn.GetFullPath() );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "An error occurred loading the symbol library table "
|
||||
"\"%s\"." ),
|
||||
symLibTableFn.GetFullPath() );
|
||||
DisplayErrorMessage( NULL, msg, ioe.What() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if any of the symbol libraries found in the appended schematic do
|
||||
// not exist in the current project are missing from the appended project symbol
|
||||
// library table.
|
||||
if( !newLibNames.IsEmpty() )
|
||||
{
|
||||
bool missingLibNames = table.IsEmpty();
|
||||
|
||||
if( !missingLibNames )
|
||||
{
|
||||
for( const auto& newLibName : newLibNames )
|
||||
{
|
||||
if( !table.HasLibrary( newLibName ) )
|
||||
{
|
||||
missingLibNames = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( missingLibNames )
|
||||
{
|
||||
msg = _( "There are library names in the loaded schematic that are missing "
|
||||
"from the loaded schematic project library table. This may result "
|
||||
"in broken symbol library links for the schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg5( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg5.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg5.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The library name already exists in the current project. Check to see if the
|
||||
// duplicate name is the same library in the current project. If it's not, it's
|
||||
// most likely that the symbol library links will be broken.
|
||||
if( !duplicateLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
bool libNameConflict = false;
|
||||
|
||||
for( const auto& duplicateLibName : duplicateLibNames )
|
||||
{
|
||||
const SYMBOL_LIB_TABLE_ROW* thisRow = nullptr;
|
||||
const SYMBOL_LIB_TABLE_ROW* otherRow = nullptr;
|
||||
|
||||
if( Prj().SchSymbolLibTable()->HasLibrary( duplicateLibName ) )
|
||||
thisRow = Prj().SchSymbolLibTable()->FindRow( duplicateLibName );
|
||||
|
||||
if( table.HasLibrary( duplicateLibName ) )
|
||||
otherRow = table.FindRow( duplicateLibName );
|
||||
|
||||
// It's in the global library table so there is no conflict.
|
||||
if( thisRow && !otherRow )
|
||||
continue;
|
||||
|
||||
if( !thisRow || !otherRow )
|
||||
continue;
|
||||
|
||||
wxFileName otherUriFileName;
|
||||
wxString thisURI = thisRow->GetFullURI( true );
|
||||
wxString otherURI = otherRow->GetFullURI( false);
|
||||
|
||||
if( otherURI.Contains( "${KIPRJMOD}" ) || otherURI.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
otherUriFileName.SetPath( fileName.GetPath() );
|
||||
otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
|
||||
otherURI = otherUriFileName.GetFullPath();
|
||||
}
|
||||
|
||||
if( thisURI != otherURI )
|
||||
{
|
||||
libNameConflict = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( libNameConflict )
|
||||
{
|
||||
msg = _( "A duplicate library name that references a different library exists "
|
||||
"in the current library table. This conflict cannot be resolved and "
|
||||
"may result in broken symbol library links for the schematic. "
|
||||
"Do you wish to continue?" );
|
||||
wxMessageDialog msgDlg6( this, msg, _( "Continue Load Schematic" ),
|
||||
wxOK | wxCANCEL | wxCANCEL_DEFAULT |
|
||||
wxCENTER | wxICON_QUESTION );
|
||||
msgDlg6.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
|
||||
|
||||
if( msgDlg6.ShowModal() == wxID_CANCEL )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All (most?) of the possible broken symbol library link cases are covered. Map the
|
||||
// new appended schematic project symbol library table entries to the current project
|
||||
// symbol library table.
|
||||
if( !newLibNames.IsEmpty() && !table.IsEmpty() )
|
||||
{
|
||||
for( const auto& libName : newLibNames )
|
||||
{
|
||||
if( !table.HasLibrary( libName )
|
||||
|| Prj().SchSymbolLibTable()->HasLibrary( libName ) )
|
||||
continue;
|
||||
|
||||
// Don't expand environment variable because KIPRJMOD will not be correct
|
||||
// for a different project.
|
||||
wxString uri = table.GetFullURI( libName, false );
|
||||
wxFileName newLib;
|
||||
|
||||
if( uri.Contains( "${KIPRJMOD}" ) || uri.Contains( "$(KIPRJMOD)" ) )
|
||||
{
|
||||
// Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
|
||||
// not expand to a valid symbol library path.
|
||||
newLib.SetPath( fileName.GetPath() );
|
||||
newLib.SetFullName( uri.AfterLast( '}' ) );
|
||||
uri = newLib.GetFullPath();
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = table.GetFullURI( libName );
|
||||
}
|
||||
|
||||
// Add the library from the imported project to the current project
|
||||
// symbol library table.
|
||||
const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
|
||||
|
||||
auto newRow = new SYMBOL_LIB_TABLE_ROW( libName, uri, row->GetType(),
|
||||
row->GetOptions(), row->GetDescr() );
|
||||
|
||||
Prj().SchSymbolLibTable()->InsertRow( newRow );
|
||||
libTableChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate sheet names in the current page.
|
||||
wxArrayString duplicateSheetNames;
|
||||
SCH_TYPE_COLLECTOR sheets;
|
||||
|
||||
sheets.Collect( currentScreen->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
|
||||
|
||||
for( i = 0; i < sheets.GetCount(); ++i )
|
||||
{
|
||||
if( newSheet->GetScreen()->GetSheet( ( ( SCH_SHEET* ) sheets[i] )->GetName() ) )
|
||||
duplicateSheetNames.Add( ( ( SCH_SHEET* ) sheets[i] )->GetName() );
|
||||
}
|
||||
|
||||
if( !duplicateSheetNames.IsEmpty() )
|
||||
{
|
||||
msg.Printf( "Duplicate sheet names exist on the current page. Do you want to "
|
||||
"automatically rename the duplicate sheet names?" );
|
||||
|
||||
if( !IsOK( this, msg ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Rename all duplicate sheet names.
|
||||
SCH_SCREEN* newScreen = newSheet->GetScreen();
|
||||
wxCHECK_MSG( newScreen, false, "No screen defined for sheet." );
|
||||
|
||||
for( const auto& duplicateName : duplicateSheetNames )
|
||||
{
|
||||
SCH_SHEET* renamedSheet = newScreen->GetSheet( duplicateName );
|
||||
|
||||
wxCHECK2_MSG( renamedSheet, continue,
|
||||
"Sheet " + duplicateName + " not found in imported schematic." );
|
||||
|
||||
timestamp_t newtimestamp = GetNewTimeStamp();
|
||||
renamedSheet->SetTimeStamp( newtimestamp );
|
||||
renamedSheet->SetName( wxString::Format( "Sheet%8.8lX", (unsigned long) newtimestamp ) );
|
||||
}
|
||||
|
||||
// Set all sheets loaded into the correct sheet file paths.
|
||||
SCH_TYPE_COLLECTOR newTopLevelSheets;
|
||||
|
||||
newTopLevelSheets.Collect( newSheet->GetScreen()->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
|
||||
|
||||
for( i = 0; i < newTopLevelSheets.GetCount(); ++i )
|
||||
{
|
||||
SCH_SHEET* tmpSheet = dynamic_cast< SCH_SHEET* >( newTopLevelSheets[i] );
|
||||
wxCHECK2( tmpSheet != nullptr, continue );
|
||||
tmpSheet->SetFileName( topLevelSheetPath + tmpSheet->GetFileName() );
|
||||
}
|
||||
|
||||
if( libTableChanged )
|
||||
Prj().SchSymbolLibTable()->Save( Prj().GetProjectPath() +
|
||||
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
|
||||
// It is finally safe to add or append the imported schematic.
|
||||
if( aSheet->GetScreen() == nullptr )
|
||||
aSheet->SetScreen( newScreen );
|
||||
else
|
||||
aSheet->GetScreen()->Append( newScreen );
|
||||
|
||||
SCH_SCREENS allScreens;
|
||||
allScreens.ReplaceDuplicateTimeStamps();
|
||||
|
||||
SCH_SCREENS screens( aSheet );
|
||||
screens.UpdateSymbolLinks( true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
||||
|
@ -527,6 +48,8 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
if( aSheet == NULL || aHierarchy == NULL )
|
||||
return false;
|
||||
|
||||
SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the schematic sheet hierarchy.
|
||||
|
||||
// Get the new texts
|
||||
DIALOG_SCH_SHEET_PROPS dlg( this, aSheet );
|
||||
|
||||
|
@ -537,11 +60,8 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
fileName.SetExt( SchematicFileExtension );
|
||||
|
||||
wxString msg;
|
||||
bool renameFile = false;
|
||||
bool loadFromFile = false;
|
||||
bool clearAnnotation = false;
|
||||
bool restoreSheet = false;
|
||||
bool isExistingSheet = false;
|
||||
SCH_SCREEN* useScreen = NULL;
|
||||
|
||||
// Relative file names are relative to the path of the current sheet. This allows for
|
||||
|
@ -575,9 +95,9 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
|
||||
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
|
||||
|
||||
if( aSheet->GetScreen() == NULL ) // New sheet.
|
||||
if( aSheet->GetScreen() == NULL ) // New sheet.
|
||||
{
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
{
|
||||
clearAnnotation = true;
|
||||
|
||||
|
@ -591,7 +111,7 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
return false;
|
||||
|
||||
}
|
||||
else // New file.
|
||||
else // New file.
|
||||
{
|
||||
aSheet->SetScreen( new SCH_SCREEN( &Kiway() ) );
|
||||
aSheet->GetScreen()->SetModify();
|
||||
|
@ -599,15 +119,14 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
aSheet->GetScreen()->SetFileName( newFilename );
|
||||
}
|
||||
}
|
||||
else // Existing sheet.
|
||||
else // Existing sheet.
|
||||
{
|
||||
bool isUndoable = true;
|
||||
bool renameFile = false;
|
||||
wxString replaceMsg;
|
||||
wxString newMsg;
|
||||
wxString noUndoMsg;
|
||||
|
||||
isExistingSheet = true;
|
||||
|
||||
// Changing the filename of a sheet can modify the full hierarchy structure
|
||||
// and can be not always undoable.
|
||||
// So prepare messages for user notifications:
|
||||
|
@ -635,7 +154,7 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
// Sheet file name changes cannot be undone.
|
||||
isUndoable = false;
|
||||
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
{
|
||||
clearAnnotation = true;
|
||||
|
||||
|
@ -647,7 +166,7 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
if( loadFromFile )
|
||||
aSheet->SetScreen( NULL );
|
||||
}
|
||||
else // Save to new file name.
|
||||
else // Save to new file name.
|
||||
{
|
||||
if( aSheet->GetScreenCount() > 1 )
|
||||
{
|
||||
|
@ -703,50 +222,43 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
|
||||
wxFileName userFileName = dlg.GetFileName();
|
||||
userFileName.SetExt( SchematicFileExtension );
|
||||
aSheet->SetFileName( userFileName.GetFullPath( wxPATH_UNIX ) );
|
||||
|
||||
if( useScreen )
|
||||
{
|
||||
// Create a temporary sheet for recursion testing to prevent a possible recursion error.
|
||||
std::unique_ptr< SCH_SHEET> tmpSheet( new SCH_SHEET );
|
||||
tmpSheet->SetName( dlg.GetSheetName() );
|
||||
tmpSheet->SetFileName( userFileName.GetFullPath( wxPATH_UNIX ) );
|
||||
tmpSheet->SetScreen( useScreen );
|
||||
|
||||
// No need to check for valid library IDs if we are using an existing screen.
|
||||
if( checkSheetForRecursion( tmpSheet.get(), aHierarchy ) )
|
||||
{
|
||||
if( restoreSheet )
|
||||
aHierarchy->LastScreen()->Append( aSheet );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's safe to set the sheet screen now.
|
||||
aSheet->SetScreen( useScreen );
|
||||
}
|
||||
else if( loadFromFile )
|
||||
{
|
||||
if( isExistingSheet )
|
||||
try
|
||||
{
|
||||
// Temporarily remove the sheet from the current schematic page so that recursion
|
||||
// and symbol library link tests can be performed with the modified sheet settings.
|
||||
restoreSheet = true;
|
||||
aHierarchy->LastScreen()->Remove( aSheet );
|
||||
}
|
||||
aSheet = pi->Load( newFilename, &Kiway(), aSheet );
|
||||
|
||||
if( !LoadSheetFromFile( aSheet, aHierarchy, newFilename ) )
|
||||
if( !pi->GetError().IsEmpty() )
|
||||
{
|
||||
DisplayErrorMessage( this,
|
||||
_( "The entire schematic could not be loaded.\n"
|
||||
"Errors occurred loading hierarchical sheets." ),
|
||||
pi->GetError() );
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
if( restoreSheet )
|
||||
aHierarchy->LastScreen()->Append( aSheet );
|
||||
msg.Printf( _( "Error occurred loading schematic file \"%s\"." ), newFilename );
|
||||
DisplayErrorMessage( this, msg, ioe.What() );
|
||||
|
||||
msg.Printf( _( "Failed to load schematic \"%s\"" ), newFilename );
|
||||
AppendMsgPanel( wxEmptyString, msg, CYAN );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( restoreSheet )
|
||||
aHierarchy->LastScreen()->Append( aSheet );
|
||||
SCH_SCREEN* screen = aSheet->GetScreen();
|
||||
|
||||
if( screen )
|
||||
screen->UpdateSymbolLinks( true );
|
||||
}
|
||||
|
||||
aSheet->SetFileName( userFileName.GetFullPath( wxPATH_UNIX ) );
|
||||
aSheet->SetFileNameSize( dlg.GetFileNameTextSize() );
|
||||
aSheet->SetName( dlg.GetSheetName() );
|
||||
aSheet->SetSheetNameSize( dlg.GetSheetNameTextSize() );
|
||||
|
@ -755,6 +267,38 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy,
|
|||
aSheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ),
|
||||
(long unsigned) aSheet->GetTimeStamp() ) );
|
||||
|
||||
// Make sure the sheet changes do not cause any recursion.
|
||||
SCH_SHEET_LIST sheetHierarchy( aSheet );
|
||||
|
||||
// Make sure files have fully qualified path and file name.
|
||||
wxFileName destFn = aHierarchy->Last()->GetFileName();
|
||||
|
||||
if( destFn.IsRelative() )
|
||||
destFn.MakeAbsolute( Prj().GetProjectPath() );
|
||||
|
||||
if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
|
||||
{
|
||||
msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
|
||||
"has the sheet \"%s\" or one of it's subsheets as a parent somewhere in "
|
||||
"the schematic hierarchy." ),
|
||||
newFilename );
|
||||
DisplayError( this, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to make sure the symbols have been remapped to the symbol library table.
|
||||
SCH_SCREENS newScreens( aSheet );
|
||||
|
||||
if( newScreens.HasNoFullyDefinedLibIds() )
|
||||
{
|
||||
msg.Printf(_( "The schematic \"%s\" has not been remapped to the symbol\nlibrary table. "
|
||||
" The project this schematic belongs to must first be remapped\nbefore it "
|
||||
"can be imported into the current project." ), fileName.GetFullName() );
|
||||
|
||||
DisplayInfoMessage( this, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( aClearAnnotationNewItems )
|
||||
*aClearAnnotationNewItems = clearAnnotation;
|
||||
|
||||
|
|
Loading…
Reference in New Issue