diff --git a/eeschema/eeschema_config.cpp b/eeschema/eeschema_config.cpp index b8a768691e..d25c02ae09 100644 --- a/eeschema/eeschema_config.cpp +++ b/eeschema/eeschema_config.cpp @@ -271,6 +271,7 @@ static const wxString RepeatStepXEntry = "RepeatStepX"; static const wxString RepeatStepYEntry = "RepeatStepY"; static const wxString RepeatLabelIncrementEntry = "RepeatLabelIncrement"; static const wxString ShowIllegalSymboLibDialog = "ShowIllegalSymbolLibDialog"; +static const wxString showSheetFileNameCaseSensitivityDlg = "ShowSheetFileNameCaseSensitivityDlg"; // Library editor wxConfig entry names. static const wxChar defaultLibWidthEntry[] = wxT( "LibeditLibWidth" ); @@ -311,7 +312,9 @@ PARAM_CFG_ARRAY& SCH_EDIT_FRAME::GetConfigurationSettings() -10, +10 ) ); m_configSettings.push_back( new PARAM_CFG_BOOL( true, ShowIllegalSymboLibDialog, &m_showIllegalSymbolLibDialog, true ) ); - + m_configSettings.push_back( new PARAM_CFG_BOOL( true, showSheetFileNameCaseSensitivityDlg, + &m_showSheetFileNameCaseSensitivityDlg, + true ) ); return m_configSettings; } @@ -407,6 +410,7 @@ void SCH_EDIT_FRAME::SaveSettings( wxConfigBase* aCfg ) aCfg->Write( FieldNamesEntry, record ); aCfg->Write( TextMarkupFlagsEntry, GetTextMarkupFlags() ); + aCfg->Write( showSheetFileNameCaseSensitivityDlg, m_showSheetFileNameCaseSensitivityDlg ); } diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index f38bdd1ad9..59660ec32f 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -240,6 +240,7 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ): m_undoItem = NULL; m_hasAutoSave = true; m_showIllegalSymbolLibDialog = true; + m_showSheetFileNameCaseSensitivityDlg = true; m_FrameSize = ConvertDialogToPixels( wxSize( 500, 350 ) ); // default in case of no prefs m_AboutTitle = "Eeschema"; diff --git a/eeschema/sch_edit_frame.h b/eeschema/sch_edit_frame.h index cd68411651..4089a6d869 100644 --- a/eeschema/sch_edit_frame.h +++ b/eeschema/sch_edit_frame.h @@ -130,6 +130,7 @@ private: bool m_autoplaceAlign; ///< align autoplaced fields to the grid bool m_footprintPreview; ///< whether to show footprint previews bool m_showIllegalSymbolLibDialog; + bool m_showSheetFileNameCaseSensitivityDlg; DIALOG_SCH_FIND* m_findReplaceDialog; STATUS_TEXT_POPUP* m_findReplaceStatusPopup; @@ -146,8 +147,6 @@ private: /// Use netcodes (net number) as net names when generating spice net lists. bool m_spiceAjustPassiveValues; -private: - /* these are PROJECT specific, not schematic editor specific wxString m_userLibraryPath; wxArrayString m_componentLibFiles; @@ -731,6 +730,19 @@ private: */ bool importFile( const wxString& aFileName, int aFileType ); + /** + * Check \a aSchematicFileName for a potential file name case sensitivity clashes. + * + * On platforms where file names are case sensitive, it is possible to schematic sheet + * file names that would cause issues on platforms where file name are case insensitive. + * File names foo.sch and Foo.sch are unique files on Linux and MacOS but on Windows + * this would result in a broken schematic. + * + * @param aSchematicFileName is the absolute path and file name of the file to test. + * @return true if the user accepts the potential file name clase risk. + */ + bool allowCaseSensitiveFileNameClashes( const wxString& aSchematicFileName ); + public: /** * Change a text type to another one. diff --git a/eeschema/sch_screen.cpp b/eeschema/sch_screen.cpp index 3c41268502..26d2ebd81e 100644 --- a/eeschema/sch_screen.cpp +++ b/eeschema/sch_screen.cpp @@ -1350,6 +1350,29 @@ bool SCH_SCREENS::HasSchematic( const wxString& aSchematicFileName ) } +bool SCH_SCREENS::CanCauseCaseSensitivityIssue( const wxString& aSchematicFileName ) const +{ + wxFileName lhs; + wxFileName rhs = aSchematicFileName; + + wxCHECK( rhs.IsAbsolute(), false ); + + for( const SCH_SCREEN* screen : m_screens ) + { + lhs = screen->GetFileName(); + + if( lhs.GetPath() != rhs.GetPath() ) + continue; + + if( lhs.GetName().CmpNoCase( rhs.GetName() ) + && lhs.GetName() != rhs.GetName() ) + return true; + } + + return false; +} + + void SCH_SCREENS::BuildClientSheetPathList() { SCH_SHEET_LIST sheetList( g_RootSheet ); diff --git a/eeschema/sch_screen.h b/eeschema/sch_screen.h index 703cd4aaad..6401b3f10e 100644 --- a/eeschema/sch_screen.h +++ b/eeschema/sch_screen.h @@ -606,6 +606,19 @@ public: void BuildClientSheetPathList(); + /** + * Check \a aSchematicFileName for a potential file name case sensitivity issue. + * + * On platforms where file names are case sensitive, it is possible to schematic sheet + * file names that would cause issues on platforms where file name are case insensitive. + * File names foo.sch and Foo.sch are unique files on Linux and MacOS but on Windows + * this would result in a broken schematic. + * + * @param aSchematicFileName is the absolute path and file name of the file to test. + * @return true if \a aSchematicFileName would cause an issue. + */ + bool CanCauseCaseSensitivityIssue( const wxString& aSchematicFileName ) const; + private: void addScreenToList( SCH_SCREEN* aScreen ); void buildScreenList( SCH_SHEET* aSheet); diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 70e9c01b47..6f125af515 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -558,8 +558,24 @@ int SCH_SHEET::ComponentCount() bool SCH_SHEET::SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen ) { + SCH_SHEET* sheet = nullptr; + SCH_SCREEN* screen = nullptr; + if( m_screen ) { + // Only check the root sheet once and don't recurse. + if( !GetParent() ) + { + sheet = this; + screen = m_screen; + + if( screen && screen->GetFileName().Cmp( aFilename ) == 0 ) + { + *aScreen = screen; + return true; + } + } + EDA_ITEM* item = m_screen->GetDrawItems(); while( item ) @@ -568,11 +584,10 @@ bool SCH_SHEET::SearchHierarchy( const wxString& aFilename, SCH_SCREEN** aScreen { // Must use the screen's path (which is always absolute) rather than the // sheet's (which could be relative). + sheet = static_cast< SCH_SHEET* >( item ); + screen = sheet->m_screen; - SCH_SHEET* sheet = (SCH_SHEET*) item; - SCH_SCREEN* screen = sheet->m_screen; - - if( screen && screen->GetFileName().CmpNoCase( aFilename ) == 0 ) + if( screen && screen->GetFileName().Cmp( aFilename ) == 0 ) { *aScreen = screen; return true; diff --git a/eeschema/sheet.cpp b/eeschema/sheet.cpp index ad2cd4dda0..b12ac9c346 100644 --- a/eeschema/sheet.cpp +++ b/eeschema/sheet.cpp @@ -569,6 +569,9 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy, if( aSheet->GetScreen() == NULL ) // New sheet. { + if( !allowCaseSensitiveFileNameClashes( newFilename ) ) + return false; + if( useScreen || loadFromFile ) // Load from existing file. { clearAnnotation = true; @@ -597,6 +600,9 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy, isExistingSheet = true; + if( !allowCaseSensitiveFileNameClashes( newFilename ) ) + return false; + // Changing the filename of a sheet can modify the full hierarchy structure // and can be not always undoable. // So prepare messages for user notifications: @@ -619,7 +625,7 @@ bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy, wxString oldFilename = aSheet->GetScreen()->GetFileName(); oldFilename.Replace( wxT( "\\" ), wxT( "/" ) ); - if( newFilename.CmpNoCase( oldFilename ) != 0 ) + if( newFilename.Cmp( oldFilename ) != 0 ) { // Sheet file name changes cannot be undone. isUndoable = false; @@ -833,10 +839,6 @@ SCH_HIERLABEL* SCH_EDIT_FRAME::ImportHierLabel( SCH_SHEET* aSheet ) } -/* - * Copy the current page or block to the clipboard, to export drawings to other applications - * (word processing ...) This is not suitable for copy command within Eeschema or Pcbnew. - */ void SCH_EDIT_FRAME::DrawCurrentSheetToClipboard() { wxRect DrawArea; @@ -909,3 +911,35 @@ void SCH_EDIT_FRAME::DrawCurrentSheetToClipboard() } +bool SCH_EDIT_FRAME::allowCaseSensitiveFileNameClashes( const wxString& aSchematicFileName ) +{ + wxString msg; + SCH_SCREENS screens; + wxFileName fn = aSchematicFileName; + + wxCHECK( fn.IsAbsolute(), false ); + + if( m_showSheetFileNameCaseSensitivityDlg + && screens.CanCauseCaseSensitivityIssue( aSchematicFileName ) ) + { + msg.Printf( _( "The file name \"%s\" can cause issues with an existing file name\n" + "already defined in the schematic on systems that support case\n" + "insensitive file names. This will cause issues if you copy this\n" + "project to an operating system that supports case insensitive file\n" + "names.\n\nDo you wish to continue?" ), + fn.GetName() ); + + wxRichMessageDialog dlg( this, msg, _( "Warning" ), + wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ); + dlg.ShowCheckBox( _( "Do not show this message again." ) ); + dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Create New Sheet" ) ), + wxMessageDialog::ButtonLabel( _( "Discard New Sheet" ) ) ); + + if( dlg.ShowModal() == wxID_NO ) + return false; + + m_showSheetFileNameCaseSensitivityDlg = !dlg.IsCheckBoxChecked(); + } + + return true; +}