Handle sheet file renaming from properties panel
When a sheet's filename field is edited through the properties panel, perform the same file operations as the sheet properties dialog: save schematic content to the new filename, handle shared screens, check for recursion, and rebuild connections. Previously only the field text was updated, leaving the actual file unchanged and causing errors on reopen. Fixes https://gitlab.com/kicad/code/kicad/-/issues/22880
This commit is contained in:
@@ -458,256 +458,8 @@ bool DIALOG_SHEET_PROPERTIES::TransferDataFromWindow()
|
||||
|
||||
bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
|
||||
{
|
||||
wxString msg;
|
||||
wxFileName sheetFileName( EnsureFileExtension( aNewFilename, FILEEXT::KiCadSchematicFileExtension ) );
|
||||
|
||||
// Sheet file names are relative to the path of the current sheet. This allows for
|
||||
// nesting of schematic files in subfolders. Screen file names are always absolute.
|
||||
SCHEMATIC& schematic = m_frame->Schematic();
|
||||
SCH_SHEET_LIST fullHierarchy = schematic.Hierarchy();
|
||||
wxFileName screenFileName( sheetFileName );
|
||||
wxFileName tmp( sheetFileName );
|
||||
SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
|
||||
|
||||
wxCHECK( currentScreen, false );
|
||||
|
||||
// SCH_SCREEN file names are always absolute.
|
||||
wxFileName currentScreenFileName = currentScreen->GetFileName();
|
||||
|
||||
if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, currentScreenFileName.GetPath() ) )
|
||||
{
|
||||
msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
|
||||
"'%s'\n"
|
||||
"against parent sheet schematic file path:\n"
|
||||
"'%s'." ),
|
||||
sheetFileName.GetPath(),
|
||||
currentScreenFileName.GetPath() );
|
||||
DisplayError( this, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString newAbsoluteFilename = screenFileName.GetFullPath();
|
||||
|
||||
// Inside Eeschema, filenames are stored using unix notation
|
||||
newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
bool renameFile = false;
|
||||
bool loadFromFile = false;
|
||||
bool clearAnnotation = false;
|
||||
bool isExistingSheet = false;
|
||||
SCH_SCREEN* useScreen = nullptr;
|
||||
SCH_SCREEN* oldScreen = nullptr;
|
||||
|
||||
// Search for a schematic file having the same filename already in use in the hierarchy
|
||||
// or on disk, in order to reuse it.
|
||||
if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
|
||||
{
|
||||
loadFromFile = wxFileExists( newAbsoluteFilename );
|
||||
|
||||
wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
|
||||
newAbsoluteFilename,
|
||||
loadFromFile ? "found" : "not found" );
|
||||
}
|
||||
|
||||
if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
|
||||
{
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
|
||||
return false;
|
||||
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
{
|
||||
clearAnnotation = true;
|
||||
|
||||
if( !IsOK( this, wxString::Format( _( "'%s' already exists." ), sheetFileName.GetFullName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ wxString::Format( _( "Link '%s' to this file?" ), newAbsoluteFilename ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If we are drawing a sheet from a design block/sheet import, we need to copy the
|
||||
// sheet to the current directory.
|
||||
else if( m_sourceSheetFilename && !m_sourceSheetFilename->IsEmpty() )
|
||||
{
|
||||
loadFromFile = true;
|
||||
|
||||
if( !wxCopyFile( *m_sourceSheetFilename, newAbsoluteFilename, false ) )
|
||||
{
|
||||
msg.Printf( _( "Failed to copy schematic file '%s' to destination '%s'." ),
|
||||
currentScreenFileName.GetFullPath(),
|
||||
newAbsoluteFilename );
|
||||
|
||||
DisplayError( m_frame, msg );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else // New file.
|
||||
{
|
||||
m_frame->InitSheet( m_sheet, newAbsoluteFilename );
|
||||
}
|
||||
}
|
||||
else // Existing sheet.
|
||||
{
|
||||
isExistingSheet = true;
|
||||
|
||||
if( !m_frame->AllowCaseSensitiveFileNameClashes( m_sheet->GetFileName(), newAbsoluteFilename ) )
|
||||
return false;
|
||||
|
||||
// We are always using here a case insensitive comparison to avoid issues
|
||||
// under Windows, although under Unix filenames are case sensitive.
|
||||
// But many users create schematic under both Unix and Windows
|
||||
// **
|
||||
// N.B. 1: aSheet->GetFileName() will return a relative path
|
||||
// aSheet->GetScreen()->GetFileName() returns a full path
|
||||
//
|
||||
// N.B. 2: newFilename uses the unix notation for separator.
|
||||
// so we must use it also to compare the old and new filenames
|
||||
wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
|
||||
oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
|
||||
{
|
||||
// Sheet file name changes cannot be undone.
|
||||
if( m_isUndoable )
|
||||
*m_isUndoable = false;
|
||||
|
||||
if( useScreen || loadFromFile ) // Load from existing file.
|
||||
{
|
||||
clearAnnotation = true;
|
||||
oldScreen = m_sheet->GetScreen();
|
||||
|
||||
if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
|
||||
newAbsoluteFilename,
|
||||
m_sheet->GetFileName(),
|
||||
sheetFileName.GetFullName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ _( "This action cannot be undone." ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( loadFromFile )
|
||||
m_sheet->SetScreen( nullptr );
|
||||
}
|
||||
else // Save to new file name.
|
||||
{
|
||||
if( m_sheet->GetScreenCount() > 1 )
|
||||
{
|
||||
if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents of '%s'?" ),
|
||||
sheetFileName.GetFullName(),
|
||||
m_sheet->GetFileName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ _( "This action cannot be undone." ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
renameFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( renameFile )
|
||||
{
|
||||
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
|
||||
|
||||
// If the associated screen is shared by more than one sheet, do not
|
||||
// change the filename of the corresponding screen here.
|
||||
// (a new screen will be created later)
|
||||
// if it is not shared, update the filename
|
||||
if( m_sheet->GetScreenCount() <= 1 )
|
||||
m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
|
||||
|
||||
try
|
||||
{
|
||||
pi->SaveSchematicFile( newAbsoluteFilename, m_sheet, &schematic );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ), newAbsoluteFilename );
|
||||
DisplayErrorMessage( this, msg, ioe.What() );
|
||||
|
||||
msg = wxString::Format( _( "Failed to save schematic '%s'" ), newAbsoluteFilename );
|
||||
m_frame->SetMsgPanel( wxEmptyString, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the associated screen is shared by more than one sheet, remove the
|
||||
// screen and reload the file to a new screen. Failure to do this will trash
|
||||
// the screen reference counting in complex hierarchies.
|
||||
if( m_sheet->GetScreenCount() > 1 )
|
||||
{
|
||||
oldScreen = m_sheet->GetScreen();
|
||||
m_sheet->SetScreen( nullptr );
|
||||
loadFromFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
|
||||
|
||||
if( useScreen )
|
||||
{
|
||||
// Create a temporary sheet for recursion testing to prevent a possible recursion error.
|
||||
std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
|
||||
|
||||
if( SCH_FIELD* srcField = m_fields->GetField( FIELD_T::SHEET_NAME ) )
|
||||
*tmpSheet->GetField( FIELD_T::SHEET_NAME ) = *srcField;
|
||||
|
||||
tmpSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( sheetFileName.GetFullPath() );
|
||||
tmpSheet->SetScreen( useScreen );
|
||||
|
||||
// No need to check for valid library IDs if we are using an existing screen.
|
||||
if( m_frame->CheckSheetForRecursion( tmpSheet.get(), ¤tSheet ) )
|
||||
return false;
|
||||
|
||||
// It's safe to set the sheet screen now.
|
||||
m_sheet->SetScreen( useScreen );
|
||||
|
||||
SCH_SHEET_LIST sheetHierarchy( m_sheet ); // The hierarchy of the loaded file.
|
||||
|
||||
sheetHierarchy.AddNewSymbolInstances( currentSheet, m_frame->Prj().GetProjectName() );
|
||||
sheetHierarchy.AddNewSheetInstances( currentSheet, fullHierarchy.GetLastVirtualPageNumber() );
|
||||
}
|
||||
else if( loadFromFile )
|
||||
{
|
||||
bool restoreSheet = false;
|
||||
|
||||
if( isExistingSheet )
|
||||
{
|
||||
// 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;
|
||||
currentSheet.LastScreen()->Remove( m_sheet );
|
||||
}
|
||||
|
||||
if( !m_frame->LoadSheetFromFile( m_sheet, ¤tSheet, newAbsoluteFilename, false, true )
|
||||
|| m_frame->CheckSheetForRecursion( m_sheet, ¤tSheet ) )
|
||||
{
|
||||
if( restoreSheet )
|
||||
{
|
||||
// If we cleared the previous screen, restore it before returning to the user
|
||||
if( oldScreen )
|
||||
m_sheet->SetScreen( oldScreen );
|
||||
|
||||
currentSheet.LastScreen()->Append( m_sheet );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( restoreSheet )
|
||||
currentSheet.LastScreen()->Append( m_sheet );
|
||||
}
|
||||
|
||||
if( m_clearAnnotationNewItems )
|
||||
*m_clearAnnotationNewItems = clearAnnotation;
|
||||
|
||||
// Rebuild the entire connection graph.
|
||||
m_frame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
|
||||
|
||||
return true;
|
||||
return m_frame->ChangeSheetFile( m_sheet, aNewFilename, m_clearAnnotationNewItems,
|
||||
m_isUndoable, m_sourceSheetFilename );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -569,6 +569,28 @@ public:
|
||||
|
||||
void InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename );
|
||||
|
||||
/**
|
||||
* Change the file backing a schematic sheet.
|
||||
*
|
||||
* Handles path normalization, case-clash checks, hierarchy search for existing screens,
|
||||
* file-exists checks, user confirmation prompts, file saving/copying, recursion checks,
|
||||
* screen linking, instance creation, LoadSheetFromFile with error recovery, and
|
||||
* RecalculateConnections + BuildSheetList repair.
|
||||
*
|
||||
* @param aSheet the sheet whose backing file is being changed
|
||||
* @param aNewFilename new relative filename (unix separators, extension already ensured)
|
||||
* @param aClearAnnotationNewItems if non-null, set true when loaded content needs
|
||||
* annotation clearing
|
||||
* @param aIsUndoable if non-null, set false when the operation is not reversible
|
||||
* @param aSourceSheetFilename if non-null and non-empty, source file to copy from
|
||||
* (design-block import)
|
||||
* @return true on success
|
||||
*/
|
||||
bool ChangeSheetFile( SCH_SHEET* aSheet, const wxString& aNewFilename,
|
||||
bool* aClearAnnotationNewItems = nullptr,
|
||||
bool* aIsUndoable = nullptr,
|
||||
const wxString* aSourceSheetFilename = nullptr );
|
||||
|
||||
/**
|
||||
* Load a the KiCad schematic file \a aFileName into the sheet \a aSheet.
|
||||
*
|
||||
|
||||
@@ -23,14 +23,20 @@
|
||||
*/
|
||||
|
||||
#include <sch_draw_panel.h>
|
||||
#include <common.h>
|
||||
#include <confirm.h>
|
||||
#include <kiface_base.h>
|
||||
#include <project.h>
|
||||
#include <math/vector2wx.h>
|
||||
#include <string_utils.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <wx_filename.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <project_sch.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sch_io/sch_io.h>
|
||||
#include <sch_io/sch_io_mgr.h>
|
||||
#include <sch_io/kicad_legacy/sch_io_kicad_legacy.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <sch_sheet_path.h>
|
||||
@@ -168,6 +174,239 @@ void SCH_EDIT_FRAME::InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::ChangeSheetFile( SCH_SHEET* aSheet, const wxString& aNewFilename,
|
||||
bool* aClearAnnotationNewItems, bool* aIsUndoable,
|
||||
const wxString* aSourceSheetFilename )
|
||||
{
|
||||
wxString msg;
|
||||
wxFileName sheetFileName( aNewFilename );
|
||||
SCHEMATIC& schematic = Schematic();
|
||||
SCH_SCREEN* currentScreen = GetCurrentSheet().LastScreen();
|
||||
|
||||
wxCHECK( currentScreen, false );
|
||||
|
||||
// SCH_SCREEN file names are always absolute.
|
||||
wxFileName currentScreenFileName = currentScreen->GetFileName();
|
||||
wxFileName screenFileName( sheetFileName );
|
||||
|
||||
if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
|
||||
currentScreenFileName.GetPath() ) )
|
||||
{
|
||||
msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
|
||||
"'%s'\n"
|
||||
"against parent sheet schematic file path:\n"
|
||||
"'%s'." ),
|
||||
sheetFileName.GetPath(),
|
||||
currentScreenFileName.GetPath() );
|
||||
DisplayError( this, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString newAbsoluteFilename = screenFileName.GetFullPath();
|
||||
newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
if( !AllowCaseSensitiveFileNameClashes( aSheet->GetFileName(), newAbsoluteFilename ) )
|
||||
return false;
|
||||
|
||||
SCH_SHEET_LIST fullHierarchy = schematic.Hierarchy();
|
||||
|
||||
bool renameFile = false;
|
||||
bool loadFromFile = false;
|
||||
bool clearAnnotation = false;
|
||||
bool isExistingSheet = false;
|
||||
SCH_SCREEN* useScreen = nullptr;
|
||||
SCH_SCREEN* oldScreen = nullptr;
|
||||
|
||||
// Search for a schematic file already in use in the hierarchy or on disk
|
||||
if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
|
||||
{
|
||||
loadFromFile = wxFileExists( newAbsoluteFilename );
|
||||
|
||||
wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
|
||||
newAbsoluteFilename,
|
||||
loadFromFile ? "found" : "not found" );
|
||||
}
|
||||
|
||||
if( aSheet->GetScreen() == nullptr )
|
||||
{
|
||||
// New sheet with no screen yet
|
||||
if( useScreen || loadFromFile )
|
||||
{
|
||||
clearAnnotation = true;
|
||||
|
||||
if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
|
||||
sheetFileName.GetFullName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ wxString::Format( _( "Link '%s' to this file?" ),
|
||||
newAbsoluteFilename ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if( aSourceSheetFilename && !aSourceSheetFilename->IsEmpty() )
|
||||
{
|
||||
// Design block / sheet import -- copy source file to destination
|
||||
loadFromFile = true;
|
||||
|
||||
if( !wxCopyFile( *aSourceSheetFilename, newAbsoluteFilename, false ) )
|
||||
{
|
||||
msg.Printf( _( "Failed to copy schematic file '%s' to destination '%s'." ),
|
||||
*aSourceSheetFilename,
|
||||
newAbsoluteFilename );
|
||||
DisplayError( this, msg );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InitSheet( aSheet, newAbsoluteFilename );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Existing sheet
|
||||
isExistingSheet = true;
|
||||
|
||||
wxString oldAbsoluteFilename = aSheet->GetScreen()->GetFileName();
|
||||
oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
|
||||
{
|
||||
// Sheet file name changes cannot be undone
|
||||
if( aIsUndoable )
|
||||
*aIsUndoable = false;
|
||||
|
||||
if( useScreen || loadFromFile )
|
||||
{
|
||||
clearAnnotation = true;
|
||||
oldScreen = aSheet->GetScreen();
|
||||
|
||||
if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
|
||||
newAbsoluteFilename,
|
||||
aSheet->GetFileName(),
|
||||
sheetFileName.GetFullName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ _( "This action cannot be undone." ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( loadFromFile )
|
||||
aSheet->SetScreen( nullptr );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save current content to new file name
|
||||
if( aSheet->GetScreenCount() > 1 )
|
||||
{
|
||||
if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
|
||||
"of '%s'?" ),
|
||||
sheetFileName.GetFullName(),
|
||||
aSheet->GetFileName() )
|
||||
+ wxT( "\n\n" )
|
||||
+ _( "This action cannot be undone." ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
renameFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( renameFile )
|
||||
{
|
||||
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
|
||||
|
||||
// Only update the screen filename when this is the sole user
|
||||
if( aSheet->GetScreenCount() <= 1 )
|
||||
aSheet->GetScreen()->SetFileName( newAbsoluteFilename );
|
||||
|
||||
try
|
||||
{
|
||||
pi->SaveSchematicFile( newAbsoluteFilename, aSheet, &schematic );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
|
||||
newAbsoluteFilename );
|
||||
DisplayErrorMessage( this, msg, ioe.What() );
|
||||
|
||||
msg = wxString::Format( _( "Failed to save schematic '%s'" ),
|
||||
newAbsoluteFilename );
|
||||
SetMsgPanel( wxEmptyString, msg );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Shared screen needs reload to maintain correct reference counting
|
||||
if( aSheet->GetScreenCount() > 1 )
|
||||
{
|
||||
oldScreen = aSheet->GetScreen();
|
||||
aSheet->SetScreen( nullptr );
|
||||
loadFromFile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SCH_SHEET_PATH& currentSheet = GetCurrentSheet();
|
||||
|
||||
if( useScreen )
|
||||
{
|
||||
// Recursion test with a temporary sheet
|
||||
std::unique_ptr<SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
|
||||
tmpSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( sheetFileName.GetFullPath() );
|
||||
tmpSheet->SetScreen( useScreen );
|
||||
|
||||
if( CheckSheetForRecursion( tmpSheet.get(), ¤tSheet ) )
|
||||
return false;
|
||||
|
||||
aSheet->SetScreen( useScreen );
|
||||
|
||||
SCH_SHEET_LIST sheetHierarchy( aSheet );
|
||||
sheetHierarchy.AddNewSymbolInstances( currentSheet, Prj().GetProjectName() );
|
||||
sheetHierarchy.AddNewSheetInstances( currentSheet,
|
||||
fullHierarchy.GetLastVirtualPageNumber() );
|
||||
}
|
||||
else if( loadFromFile )
|
||||
{
|
||||
bool restoreSheet = false;
|
||||
|
||||
if( isExistingSheet )
|
||||
{
|
||||
restoreSheet = true;
|
||||
currentSheet.LastScreen()->Remove( aSheet );
|
||||
}
|
||||
|
||||
if( !LoadSheetFromFile( aSheet, ¤tSheet, newAbsoluteFilename, false, true )
|
||||
|| CheckSheetForRecursion( aSheet, ¤tSheet ) )
|
||||
{
|
||||
if( restoreSheet )
|
||||
{
|
||||
if( oldScreen )
|
||||
aSheet->SetScreen( oldScreen );
|
||||
|
||||
currentSheet.LastScreen()->Append( aSheet );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( restoreSheet )
|
||||
currentSheet.LastScreen()->Append( aSheet );
|
||||
}
|
||||
|
||||
if( aClearAnnotationNewItems )
|
||||
*aClearAnnotationNewItems = clearAnnotation;
|
||||
|
||||
RecalculateConnections( nullptr, GLOBAL_CLEANUP );
|
||||
|
||||
SCH_SHEET_LIST repairedList;
|
||||
repairedList.BuildSheetList( &schematic.Root(), true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SCH_EDIT_FRAME::LoadSheetFromFile( SCH_SHEET* aSheet, SCH_SHEET_PATH* aCurrentSheet,
|
||||
const wxString& aFileName, bool aSkipRecursionCheck,
|
||||
bool aSkipLibCheck )
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
|
||||
#include <font/fontconfig.h>
|
||||
#include <pgm_base.h>
|
||||
#include <common.h>
|
||||
#include <confirm.h>
|
||||
#include <connection_graph.h>
|
||||
#include <properties/pg_editors.h>
|
||||
#include <properties/pg_properties.h>
|
||||
#include <properties/property_mgr.h>
|
||||
#include <sch_commit.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sch_sheet.h>
|
||||
#include <symbol_edit_frame.h>
|
||||
#include <symbol_viewer_frame.h>
|
||||
#include <schematic.h>
|
||||
@@ -39,6 +42,8 @@
|
||||
#include <string_utils.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tools/sch_selection_tool.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
#include <wx_filename.h>
|
||||
#include <set>
|
||||
|
||||
static const wxString MISSING_FIELD_SENTINEL = wxS( "\uE000" );
|
||||
@@ -436,6 +441,28 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
|
||||
}
|
||||
}
|
||||
|
||||
// Changing a sheet's filename field requires file operations to match the dialog behavior.
|
||||
if( item->Type() == SCH_FIELD_T
|
||||
&& m_frame->IsType( FRAME_SCH )
|
||||
&& property->Name() == wxT( "Text" ) )
|
||||
{
|
||||
SCH_FIELD* field = static_cast<SCH_FIELD*>( item );
|
||||
SCH_SHEET* sheet = dynamic_cast<SCH_SHEET*>( item->GetParent() );
|
||||
|
||||
if( sheet && field->GetId() == FIELD_T::SHEET_FILENAME )
|
||||
{
|
||||
SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_frame );
|
||||
|
||||
if( !handleSheetFilenameChange( editFrame, sheet, changes, newValue.GetString() ) )
|
||||
{
|
||||
UpdateData();
|
||||
return;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( item->Type() == SCH_TABLECELL_T )
|
||||
changes.Modify( item->GetParent(), screen, RECURSE_MODE::NO_RECURSE );
|
||||
else
|
||||
@@ -464,6 +491,38 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
|
||||
}
|
||||
|
||||
|
||||
bool SCH_PROPERTIES_PANEL::handleSheetFilenameChange( SCH_EDIT_FRAME* aFrame, SCH_SHEET* aSheet,
|
||||
SCH_COMMIT& aChanges,
|
||||
const wxString& aNewFilename )
|
||||
{
|
||||
wxString newFilename = EnsureFileExtension( aNewFilename, FILEEXT::KiCadSchematicFileExtension );
|
||||
|
||||
if( newFilename.IsEmpty() || !IsFullFileNameValid( newFilename ) )
|
||||
{
|
||||
DisplayError( aFrame, _( "A sheet must have a valid file name." ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize separators to unix notation
|
||||
newFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
wxString oldFilename = aSheet->GetFileName();
|
||||
oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
|
||||
|
||||
if( newFilename == oldFilename )
|
||||
return true;
|
||||
|
||||
if( !aFrame->ChangeSheetFile( aSheet, newFilename ) )
|
||||
return false;
|
||||
|
||||
SCH_SCREEN* currentScreen = aFrame->GetCurrentSheet().LastScreen();
|
||||
aChanges.Modify( aSheet, currentScreen, RECURSE_MODE::NO_RECURSE );
|
||||
aSheet->SetFileName( newFilename );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SCH_PROPERTIES_PANEL::OnLanguageChanged( wxCommandEvent& aEvent )
|
||||
{
|
||||
PROPERTIES_PANEL::OnLanguageChanged( aEvent );
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
class SELECTION;
|
||||
class SCHEMATIC;
|
||||
class SCH_BASE_FRAME;
|
||||
class SCH_COMMIT;
|
||||
class SCH_EDIT_FRAME;
|
||||
class SCH_SHEET;
|
||||
class PROPERTY_MANAGER;
|
||||
class PG_UNIT_EDITOR;
|
||||
class PG_CHECKBOX_EDITOR;
|
||||
@@ -55,6 +58,9 @@ protected:
|
||||
void valueChanging( wxPropertyGridEvent& aEvent ) override;
|
||||
void valueChanged( wxPropertyGridEvent& aEvent ) override;
|
||||
|
||||
bool handleSheetFilenameChange( SCH_EDIT_FRAME* aFrame, SCH_SHEET* aSheet,
|
||||
SCH_COMMIT& aChanges, const wxString& aNewFilename );
|
||||
|
||||
void OnLanguageChanged( wxCommandEvent& aEvent ) override;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user