Use new file formats for copy and paste in schematic and symbol editors.

This commit is contained in:
Wayne Stambaugh 2020-05-13 17:58:30 -04:00
parent 3a9746c657
commit ad88874adf
6 changed files with 111 additions and 66 deletions

View File

@ -48,7 +48,6 @@
#include <sch_component.h> #include <sch_component.h>
#include <sch_edit_frame.h> // CMP_ORIENT_XXX #include <sch_edit_frame.h> // CMP_ORIENT_XXX
#include <sch_field.h> #include <sch_field.h>
#include <sch_file_versions.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_junction.h> #include <sch_junction.h>
#include <sch_no_connect.h> #include <sch_no_connect.h>
@ -95,7 +94,7 @@ void SCH_SEXPR_PARSER::ParseLib( LIB_PART_MAP& aSymbolLibMap )
{ {
m_unit = 1; m_unit = 1;
m_convert = 1; m_convert = 1;
LIB_PART* symbol = ParseSymbol( aSymbolLibMap ); LIB_PART* symbol = ParseSymbol( aSymbolLibMap, m_requiredVersion );
aSymbolLibMap[symbol->GetName()] = symbol; aSymbolLibMap[symbol->GetName()] = symbol;
} }
else 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, wxCHECK_MSG( CurTok() == T_symbol, nullptr,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a symbol." ) ); 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; LIB_ITEM* item;
std::unique_ptr<LIB_PART> symbol( new LIB_PART( wxEmptyString ) ); std::unique_ptr<LIB_PART> symbol( new LIB_PART( wxEmptyString ) );
m_requiredVersion = aFileVersion;
symbol->SetUnitCount( 1 ); symbol->SetUnitCount( 1 );
m_fieldId = MANDATORY_FIELDS; 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 */ ); wxCHECK( aSheet != nullptr, /* void */ );
@ -1869,30 +1869,42 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
wxCHECK( screen != nullptr, /* void */ ); wxCHECK( screen != nullptr, /* void */ );
if( aIsCopyableOnly )
m_requiredVersion = aFileVersion;
T token; T token;
NeedLEFT(); if( !aIsCopyableOnly )
NextTok(); {
NeedLEFT();
NextTok();
if( CurTok() != T_kicad_sch ) if( CurTok() != T_kicad_sch )
Expecting( "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() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
if( aIsCopyableOnly && token == T_EOF )
break;
if( token != T_LEFT ) if( token != T_LEFT )
Expecting( T_LEFT ); Expecting( T_LEFT );
token = NextTok(); token = NextTok();
if( token == T_page && m_requiredVersion <= 20200506 ) if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 )
token = T_paper; token = T_paper;
switch( token ) switch( token )
{ {
case T_paper: case T_paper:
{ {
if( aIsCopyableOnly )
Unexpected( T_paper );
PAGE_INFO pageInfo; PAGE_INFO pageInfo;
parsePAGE_INFO( pageInfo ); parsePAGE_INFO( pageInfo );
screen->SetPageSettings( pageInfo ); screen->SetPageSettings( pageInfo );
@ -1901,6 +1913,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
case T_page: case T_page:
{ {
if( aIsCopyableOnly )
Unexpected( T_page );
// Only saved for top-level sniffing in Kicad Manager frame and other external // Only saved for top-level sniffing in Kicad Manager frame and other external
// tool usage with flat hierarchies // tool usage with flat hierarchies
NeedSYMBOLorNUMBER(); NeedSYMBOLorNUMBER();
@ -1911,6 +1926,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
case T_title_block: case T_title_block:
{ {
if( aIsCopyableOnly )
Unexpected( T_title_block );
TITLE_BLOCK tb; TITLE_BLOCK tb;
parseTITLE_BLOCK( tb ); parseTITLE_BLOCK( tb );
screen->SetTitleBlock( tb ); screen->SetTitleBlock( tb );
@ -1919,6 +1937,9 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
case T_lib_symbols: case T_lib_symbols:
{ {
if( aIsCopyableOnly )
Unexpected( T_lib_symbols );
// Dummy map. No derived symbols are allowed in the library cache. // Dummy map. No derived symbols are allowed in the library cache.
LIB_PART_MAP symbolLibMap; LIB_PART_MAP symbolLibMap;
@ -1932,7 +1953,7 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
switch( token ) switch( token )
{ {
case T_symbol: case T_symbol:
screen->AddLibSymbol( ParseSymbol( symbolLibMap, true ) ); screen->AddLibSymbol( ParseSymbol( symbolLibMap ) );
break; break;
default: default:
@ -1991,10 +2012,16 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
break; break;
case T_symbol_instances: case T_symbol_instances:
if( aIsCopyableOnly )
Unexpected( T_symbol_instances );
parseSchSymbolInstances( screen ); parseSchSymbolInstances( screen );
break; break;
case T_bus_alias: case T_bus_alias:
if( aIsCopyableOnly )
Unexpected( T_bus_alias );
parseBusAlias( screen ); parseBusAlias( screen );
break; break;
@ -2005,7 +2032,8 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet )
} }
} }
screen->UpdateLocalLibSymbolLinks(); if( !aIsCopyableOnly )
screen->UpdateLocalLibSymbolLinks();
} }

View File

@ -36,6 +36,7 @@
#include <class_library.h> #include <class_library.h>
#include <schematic_lexer.h> #include <schematic_lexer.h>
#include <sch_file_versions.h>
#include <default_values.h> // For some default values #include <default_values.h> // For some default values
@ -222,18 +223,30 @@ public:
void ParseLib( LIB_PART_MAP& aSymbolLibMap ); 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(); 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. * @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 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 * Return whether a version number, if any was parsed, was too recent

View File

@ -389,10 +389,8 @@ public:
wxString GetFileName() const { return m_libFileName.GetFullPath(); } wxString GetFileName() const { return m_libFileName.GetFullPath(); }
static LIB_PART* LoadPart( LINE_READER& aReader, int aMajorVersion, int aMinorVersion, static void SaveSymbol( LIB_PART* aSymbol, OUTPUTFORMATTER& aFormatter,
LIB_PART_MAP* aMap = nullptr ); 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, void SCH_SEXPR_PLUGIN::Save( const wxString& aFileName, SCH_SHEET* aSheet, KIWAY* aKiway,
const PROPERTIES* aProperties ) 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() void SCH_SEXPR_PLUGIN_CACHE::Save()
{ {
if( !m_isModified ) 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, LIB_PART* SCH_SEXPR_PLUGIN::ParsePart( LINE_READER& aReader, int aFileVersion )
int aMinorVersion )
{ {
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 );
} }

View File

@ -24,6 +24,7 @@
#include <memory> #include <memory>
#include <sch_io_mgr.h> #include <sch_io_mgr.h>
#include <sch_file_versions.h>
#include <stack> #include <stack>
@ -87,8 +88,8 @@ public:
SCH_SHEET* aAppendToMe = nullptr, SCH_SHEET* aAppendToMe = nullptr,
const PROPERTIES* aProperties = nullptr ) override; const PROPERTIES* aProperties = nullptr ) override;
void LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen, void LoadContent( LINE_READER& aReader, SCH_SHEET* aSheet,
int version = EESCHEMA_VERSION ); int aVersion = SEXPR_SCHEMATIC_FILE_VERSION );
void Save( const wxString& aFileName, SCH_SHEET* aSheet, KIWAY* aKiway, void Save( const wxString& aFileName, SCH_SHEET* aSheet, KIWAY* aKiway,
const PROPERTIES* aProperties = nullptr ) override; const PROPERTIES* aProperties = nullptr ) override;
@ -121,7 +122,8 @@ public:
const wxString& GetError() const override { return m_error; } 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 ); static void FormatPart( LIB_PART* aPart, OUTPUTFORMATTER& aFormatter );
private: private:

View File

@ -38,7 +38,7 @@
#include <dialogs/dialog_edit_one_field.h> #include <dialogs/dialog_edit_one_field.h>
#include <dialogs/dialog_edit_component_in_lib.h> #include <dialogs/dialog_edit_component_in_lib.h>
#include <dialogs/dialog_lib_edit_pin_table.h> #include <dialogs/dialog_lib_edit_pin_table.h>
#include <sch_legacy_plugin.h> #include <sch_sexpr_plugin.h>
#include <lib_text.h> #include <lib_text.h>
#include "lib_edit_tool.h" #include "lib_edit_tool.h"
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
@ -627,7 +627,7 @@ int LIB_EDIT_TOOL::Copy( const TOOL_EVENT& aEvent )
LIB_PART* partCopy = new LIB_PART( *part ); LIB_PART* partCopy = new LIB_PART( *part );
STRING_FORMATTER formatter; STRING_FORMATTER formatter;
SCH_LEGACY_PLUGIN::FormatPart( partCopy, formatter ); SCH_SEXPR_PLUGIN::FormatPart( partCopy, formatter );
delete partCopy; delete partCopy;
@ -654,8 +654,7 @@ int LIB_EDIT_TOOL::Paste( const TOOL_EVENT& aEvent )
try try
{ {
reader.ReadLine(); newPart = SCH_SEXPR_PLUGIN::ParsePart( reader );
newPart = SCH_LEGACY_PLUGIN::ParsePart( reader );
} }
catch( IO_ERROR& ) catch( IO_ERROR& )
{ {

View File

@ -38,7 +38,7 @@
#include <netlist_exporters/netlist_exporter_pspice.h> #include <netlist_exporters/netlist_exporter_pspice.h>
#include <netlist_object.h> #include <netlist_object.h>
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
#include <sch_legacy_plugin.h> #include <sch_sexpr_plugin.h>
#include <sch_line.h> #include <sch_line.h>
#include <sch_painter.h> #include <sch_painter.h>
#include <sch_sheet.h> #include <sch_sheet.h>
@ -1106,7 +1106,7 @@ bool SCH_EDITOR_CONTROL::doCopy()
} }
STRING_FORMATTER formatter; STRING_FORMATTER formatter;
SCH_LEGACY_PLUGIN plugin; SCH_SEXPR_PLUGIN plugin;
plugin.Format( &selection, &formatter ); plugin.Format( &selection, &formatter );
@ -1177,18 +1177,22 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
return 0; return 0;
STRING_LINE_READER reader( text, "Clipboard" ); 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 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 // 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; bool forceKeepAnnotations = false;
@ -1206,7 +1210,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
if( forceDropAnnotations ) if( forceDropAnnotations )
dropAnnotations = true; 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. // else. Pull them back out to start with.
// //
EDA_ITEMS loadedItems; EDA_ITEMS loadedItems;
@ -1217,7 +1221,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
if( destFn.IsRelative() ) if( destFn.IsRelative() )
destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() ); destFn.MakeAbsolute( m_frame->Prj().GetProjectPath() );
for( SCH_ITEM* item : paste_screen.Items() ) for( SCH_ITEM* item : paste_screen->Items() )
{ {
loadedItems.push_back( item ); 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 // Remove the references from our temporary screen to prevent freeing on the DTOR
paste_screen.Clear( false ); 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();
for( unsigned i = 0; i < loadedItems.size(); ++i ) 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; 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 ) if( dropAnnotations )
{ {
const_cast<KIID&>( component->m_Uuid ) = KIID(); const_cast<KIID&>( component->m_Uuid ) = KIID();
@ -1280,20 +1294,6 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
component->ClearAnnotation( nullptr ); component->ClearAnnotation( nullptr );
component->SetUnit( unit ); 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 else
{ {