From ad88874adf40249c0c45a21adb8c7474b3af358e Mon Sep 17 00:00:00 2001 From: Wayne Stambaugh Date: Wed, 13 May 2020 17:58:30 -0400 Subject: [PATCH] Use new file formats for copy and paste in schematic and symbol editors. --- eeschema/sch_sexpr_parser.cpp | 52 ++++++++++++++++++++------ eeschema/sch_sexpr_parser.h | 19 ++++++++-- eeschema/sch_sexpr_plugin.cpp | 37 +++++++++--------- eeschema/sch_sexpr_plugin.h | 8 ++-- eeschema/tools/lib_edit_tool.cpp | 7 ++-- eeschema/tools/sch_editor_control.cpp | 54 +++++++++++++-------------- 6 files changed, 111 insertions(+), 66 deletions(-) diff --git a/eeschema/sch_sexpr_parser.cpp b/eeschema/sch_sexpr_parser.cpp index ea1b2564a4..905c3f11c4 100644 --- a/eeschema/sch_sexpr_parser.cpp +++ b/eeschema/sch_sexpr_parser.cpp @@ -48,7 +48,6 @@ #include #include // CMP_ORIENT_XXX #include -#include #include #include #include @@ -95,7 +94,7 @@ void SCH_SEXPR_PARSER::ParseLib( LIB_PART_MAP& aSymbolLibMap ) { m_unit = 1; m_convert = 1; - LIB_PART* symbol = ParseSymbol( aSymbolLibMap ); + LIB_PART* symbol = ParseSymbol( aSymbolLibMap, m_requiredVersion ); aSymbolLibMap[symbol->GetName()] = symbol; } else @@ -106,7 +105,7 @@ void SCH_SEXPR_PARSER::ParseLib( LIB_PART_MAP& aSymbolLibMap ) } -LIB_PART* SCH_SEXPR_PARSER::ParseSymbol( LIB_PART_MAP& aSymbolLibMap, bool aIsSchematicLib ) +LIB_PART* SCH_SEXPR_PARSER::ParseSymbol( LIB_PART_MAP& aSymbolLibMap, int aFileVersion ) { wxCHECK_MSG( CurTok() == T_symbol, nullptr, wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a symbol." ) ); @@ -118,6 +117,7 @@ LIB_PART* SCH_SEXPR_PARSER::ParseSymbol( LIB_PART_MAP& aSymbolLibMap, bool aIsSc LIB_ITEM* item; std::unique_ptr symbol( new LIB_PART( wxEmptyString ) ); + m_requiredVersion = aFileVersion; symbol->SetUnitCount( 1 ); m_fieldId = MANDATORY_FIELDS; @@ -1861,7 +1861,7 @@ void SCH_SEXPR_PARSER::parseSchSymbolInstances( SCH_SCREEN* aScreen ) } -void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) +void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopyableOnly, int aFileVersion ) { wxCHECK( aSheet != nullptr, /* void */ ); @@ -1869,30 +1869,42 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) wxCHECK( screen != nullptr, /* void */ ); + if( aIsCopyableOnly ) + m_requiredVersion = aFileVersion; + T token; - NeedLEFT(); - NextTok(); + if( !aIsCopyableOnly ) + { + NeedLEFT(); + NextTok(); - if( CurTok() != T_kicad_sch ) - Expecting( "kicad_sch" ); + if( CurTok() != T_kicad_sch ) + Expecting( "kicad_sch" ); - parseHeader( T_kicad_sch, SEXPR_SCHEMATIC_FILE_VERSION ); + parseHeader( T_kicad_sch, SEXPR_SCHEMATIC_FILE_VERSION ); + } for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { + if( aIsCopyableOnly && token == T_EOF ) + break; + if( token != T_LEFT ) Expecting( T_LEFT ); token = NextTok(); - if( token == T_page && m_requiredVersion <= 20200506 ) + if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 ) token = T_paper; switch( token ) { case T_paper: { + if( aIsCopyableOnly ) + Unexpected( T_paper ); + PAGE_INFO pageInfo; parsePAGE_INFO( pageInfo ); screen->SetPageSettings( pageInfo ); @@ -1901,6 +1913,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) case T_page: { + if( aIsCopyableOnly ) + Unexpected( T_page ); + // Only saved for top-level sniffing in Kicad Manager frame and other external // tool usage with flat hierarchies NeedSYMBOLorNUMBER(); @@ -1911,6 +1926,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) case T_title_block: { + if( aIsCopyableOnly ) + Unexpected( T_title_block ); + TITLE_BLOCK tb; parseTITLE_BLOCK( tb ); screen->SetTitleBlock( tb ); @@ -1919,6 +1937,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) case T_lib_symbols: { + if( aIsCopyableOnly ) + Unexpected( T_lib_symbols ); + // Dummy map. No derived symbols are allowed in the library cache. LIB_PART_MAP symbolLibMap; @@ -1932,7 +1953,7 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) switch( token ) { case T_symbol: - screen->AddLibSymbol( ParseSymbol( symbolLibMap, true ) ); + screen->AddLibSymbol( ParseSymbol( symbolLibMap ) ); break; default: @@ -1991,10 +2012,16 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) break; case T_symbol_instances: + if( aIsCopyableOnly ) + Unexpected( T_symbol_instances ); + parseSchSymbolInstances( screen ); break; case T_bus_alias: + if( aIsCopyableOnly ) + Unexpected( T_bus_alias ); + parseBusAlias( screen ); break; @@ -2005,7 +2032,8 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet ) } } - screen->UpdateLocalLibSymbolLinks(); + if( !aIsCopyableOnly ) + screen->UpdateLocalLibSymbolLinks(); } diff --git a/eeschema/sch_sexpr_parser.h b/eeschema/sch_sexpr_parser.h index af4a746295..a1f89280e5 100644 --- a/eeschema/sch_sexpr_parser.h +++ b/eeschema/sch_sexpr_parser.h @@ -36,6 +36,7 @@ #include #include +#include #include // For some default values @@ -222,18 +223,30 @@ public: void ParseLib( LIB_PART_MAP& aSymbolLibMap ); - LIB_PART* ParseSymbol( LIB_PART_MAP& aSymbolLibMap, bool aIsSchematicLib = false ); + LIB_PART* ParseSymbol( LIB_PART_MAP& aSymbolLibMap, + int aFileVersion = SEXPR_SYMBOL_LIB_FILE_VERSION ); LIB_ITEM* ParseDrawItem(); /** - * Parse a single schematic file into \a aSheet. + * Parse the internal #LINE_READER object into \a aSheet. + * + * When \a aIsCopyableOnly is true, only schematic objects that are viewable on the canvas + * for copy and paste purposes are parsed. Other schematic content such as bus definitions + * or instance data will throw an #IO_ERROR exception. + * + * When \a aIsCopyableOnly is false, full schematic file parsing is performed. * * @note This does not load any sub-sheets or decent complex sheet hierarchies. * * @param aSheet The #SCH_SHEET object to store the parsed schematic file. + * @param aIsCopyableOnly Load only the schematic objects that can be copied into \a aSheet + * if true. Otherwise, load the full schematic file format. + * @param aFileVersion The schematic file version to parser. Defaults to the schematic + * file being parsed when \a aIsCopyableOnly is false. */ - void ParseSchematic( SCH_SHEET* aSheet ); + void ParseSchematic( SCH_SHEET* aSheet, bool aIsCopyablyOnly = false, + int aFileVersion = SEXPR_SCHEMATIC_FILE_VERSION ); /** * Return whether a version number, if any was parsed, was too recent diff --git a/eeschema/sch_sexpr_plugin.cpp b/eeschema/sch_sexpr_plugin.cpp index 11f293727e..6f415b27a6 100644 --- a/eeschema/sch_sexpr_plugin.cpp +++ b/eeschema/sch_sexpr_plugin.cpp @@ -389,10 +389,8 @@ public: wxString GetFileName() const { return m_libFileName.GetFullPath(); } - static LIB_PART* LoadPart( LINE_READER& aReader, int aMajorVersion, int aMinorVersion, - LIB_PART_MAP* aMap = nullptr ); - static void SaveSymbol( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter, - int aNestLevel = 0, const wxString& aLibName = wxEmptyString ); + static void SaveSymbol( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter, + int aNestLevel = 0, const wxString& aLibName = wxEmptyString ); }; @@ -569,6 +567,16 @@ void SCH_SEXPR_PLUGIN::loadFile( const wxString& aFileName, SCH_SHEET* aSheet ) } +void SCH_SEXPR_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet, int aFileVersion ) +{ + wxCHECK( aSheet, /* void */ ); + + SCH_SEXPR_PARSER parser( &aReader ); + + parser.ParseSchematic( aSheet, true, aFileVersion ); +} + + void SCH_SEXPR_PLUGIN::Save( const wxString& aFileName, SCH_SHEET* aSheet, KIWAY* aKiway, const PROPERTIES* aProperties ) { @@ -1390,16 +1398,6 @@ void SCH_SEXPR_PLUGIN_CACHE::Load() } -LIB_PART* SCH_SEXPR_PLUGIN_CACHE::LoadPart( LINE_READER& aReader, int aMajorVersion, - int aMinorVersion, LIB_PART_MAP* aMap ) -{ - std::unique_ptr< LIB_PART > part( new LIB_PART( wxEmptyString ) ); - - return part.release(); -} - - - void SCH_SEXPR_PLUGIN_CACHE::Save() { if( !m_isModified ) @@ -2285,10 +2283,15 @@ bool SCH_SEXPR_PLUGIN::IsSymbolLibWritable( const wxString& aLibraryPath ) } -LIB_PART* SCH_SEXPR_PLUGIN::ParsePart( LINE_READER& reader, int aMajorVersion, - int aMinorVersion ) +LIB_PART* SCH_SEXPR_PLUGIN::ParsePart( LINE_READER& aReader, int aFileVersion ) { - return SCH_SEXPR_PLUGIN_CACHE::LoadPart( reader, aMajorVersion, aMinorVersion ); + LIB_PART_MAP map; + SCH_SEXPR_PARSER parser( &aReader ); + + parser.NeedLEFT(); + parser.NextTok(); + + return parser.ParseSymbol( map, aFileVersion ); } diff --git a/eeschema/sch_sexpr_plugin.h b/eeschema/sch_sexpr_plugin.h index 4b242734ad..686b26b98e 100644 --- a/eeschema/sch_sexpr_plugin.h +++ b/eeschema/sch_sexpr_plugin.h @@ -24,6 +24,7 @@ #include #include +#include #include @@ -87,8 +88,8 @@ public: SCH_SHEET* aAppendToMe = nullptr, const PROPERTIES* aProperties = nullptr ) override; - void LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen, - int version = EESCHEMA_VERSION ); + void LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet, + int aVersion = SEXPR_SCHEMATIC_FILE_VERSION ); void Save( const wxString& aFileName, SCH_SHEET* aSheet, KIWAY* aKiway, const PROPERTIES* aProperties = nullptr ) override; @@ -121,7 +122,8 @@ public: const wxString& GetError() const override { return m_error; } - static LIB_PART* ParsePart( LINE_READER& aReader, int majorVersion = 0, int minorVersion = 0 ); + static LIB_PART* ParsePart( LINE_READER& aReader, + int aVersion = SEXPR_SCHEMATIC_FILE_VERSION ); static void FormatPart( LIB_PART* aPart, OUTPUTFORMATTER& aFormatter ); private: diff --git a/eeschema/tools/lib_edit_tool.cpp b/eeschema/tools/lib_edit_tool.cpp index ad9b6fe647..5fa713cfdd 100644 --- a/eeschema/tools/lib_edit_tool.cpp +++ b/eeschema/tools/lib_edit_tool.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include "lib_edit_tool.h" #include // for KiROUND @@ -627,7 +627,7 @@ int LIB_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent ) LIB_PART* partCopy = new LIB_PART( *part ); STRING_FORMATTER formatter; - SCH_LEGACY_PLUGIN::FormatPart( partCopy, formatter ); + SCH_SEXPR_PLUGIN::FormatPart( partCopy, formatter ); delete partCopy; @@ -654,8 +654,7 @@ int LIB_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent ) try { - reader.ReadLine(); - newPart = SCH_LEGACY_PLUGIN::ParsePart( reader ); + newPart = SCH_SEXPR_PLUGIN::ParsePart( reader ); } catch( IO_ERROR& ) { diff --git a/eeschema/tools/sch_editor_control.cpp b/eeschema/tools/sch_editor_control.cpp index a43c8db15a..b9ccf82f34 100644 --- a/eeschema/tools/sch_editor_control.cpp +++ b/eeschema/tools/sch_editor_control.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include @@ -1106,7 +1106,7 @@ bool SCH_EDITOR_CONTROL::doCopy() } STRING_FORMATTER formatter; - SCH_LEGACY_PLUGIN plugin; + SCH_SEXPR_PLUGIN plugin; plugin.Format( &selection, &formatter ); @@ -1177,18 +1177,22 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) return 0; STRING_LINE_READER reader( text, "Clipboard" ); - SCH_LEGACY_PLUGIN plugin; + SCH_SEXPR_PLUGIN plugin; - SCH_SCREEN paste_screen( &m_frame->GetScreen()->Kiway() ); + SCH_SHEET paste_sheet; + SCH_SCREEN* paste_screen = new SCH_SCREEN( &m_frame->GetScreen()->Kiway() ); + + // Screen object on heap is owned by the sheet. + paste_sheet.SetScreen( paste_screen ); try { - plugin.LoadContent( reader, &paste_screen ); + plugin.LoadContent( reader, &paste_sheet ); } - catch( IO_ERROR& ) + catch( IO_ERROR& ioe ) { // If it wasn't content, then paste as text - paste_screen.Append( new SCH_TEXT( wxPoint( 0, 0 ), text ) ); + paste_screen->Append( new SCH_TEXT( wxPoint( 0, 0 ), text ) ); } bool forceKeepAnnotations = false; @@ -1206,7 +1210,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) if( forceDropAnnotations ) dropAnnotations = true; - // SCH_LEGACY_PLUGIN added the items to the paste screen, but not to the view or anything + // 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; @@ -1217,7 +1221,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) if( destFn.IsRelative() ) destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() ); - for( SCH_ITEM* item : paste_screen.Items() ) + for( SCH_ITEM* item : paste_screen->Items() ) { loadedItems.push_back( item ); @@ -1258,10 +1262,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) } // Remove the references from our temporary screen to prevent freeing on the DTOR - paste_screen.Clear( false ); - - // Now we can resolve the components and add everything to the screen, view, etc. - SYMBOL_LIB_TABLE* symLibTable = m_frame->Prj().SchSymbolLibTable(); + paste_screen->Clear( false ); for( unsigned i = 0; i < loadedItems.size(); ++i ) { @@ -1271,6 +1272,19 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) { SCH_COMPONENT* component = (SCH_COMPONENT*) item; + // The library symbol gets set from the cached library symbols in the current + // schematic not the symbol libraries. The cached library symbol may have + // changed from the original library symbol which would cause the copy to + // be incorrect. + SCH_SCREEN* currentScreen = m_frame->GetScreen(); + + wxCHECK2( currentScreen, continue ); + + auto it = currentScreen->GetLibSymbols().find( component->GetSchSymbolLibraryName() ); + + if( it != currentScreen->GetLibSymbols().end() ) + component->SetLibSymbol( new LIB_PART( *it->second ) ); + if( dropAnnotations ) { const_cast( component->m_Uuid ) = KIID(); @@ -1280,20 +1294,6 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent ) component->ClearAnnotation( nullptr ); component->SetUnit( unit ); } - - LIB_PART* libSymbol = symLibTable->LoadSymbol( component->GetLibId() ); - - if( libSymbol ) - { - component->SetLibSymbol( new LIB_PART( *libSymbol ) ); - } - else - { - DisplayError( m_frame, - wxString::Format( _( "Symbol '%s' not found in library '%s'." ), - component->GetLibId().GetLibItemName().wx_str(), - component->GetLibId().GetLibNickname().wx_str() ) ); - } } else {