@ -1243,14 +1243,12 @@ bool SCH_EDITOR_CONTROL::doCopy()
}
}
m_supplementaryClipboardInstances . Clear ( ) ;
schematic . GetSheets ( ) . GetSymbols ( m_supplementaryClipboardInstances , true , true ) ;
m_supplementaryClipboardPath = m_frame - > GetCurrentSheet ( ) . Path ( ) ;
STRING_FORMATTER formatter ;
SCH_SEXPR_PLUGIN plugin ;
SCH_SHEET_LIST hiearchy = schematic . GetSheets ( ) ;
SCH_SHEET_PATH selPath = m_frame - > GetCurrentSheet ( ) ;
plugin . Format ( & selection , & m_frame - > GetCurrentSheet ( ) , & formatter ) ;
plugin . Format ( & selection , & selPath , & hiearchy , & formatter ) ;
return m_toolMgr - > SaveClipboard ( formatter . GetString ( ) ) ;
}
@ -1302,60 +1300,118 @@ int SCH_EDITOR_CONTROL::Copy( const TOOL_EVENT& aEvent )
}
void SCH_EDITOR_CONTROL : : updatePastedInstances ( const SCH_SHEET_PATH & aPastePath ,
const KIID_PATH & aClipPath , SCH_SHEET * aSheet ,
bool aForceKeepAnnotations )
void SCH_EDITOR_CONTROL : : updatePastedSymbol ( SCH_COMPONENT * aSymbol , SCH_SCREEN * aPasteScreen ,
const SCH_SHEET_PATH & aPastePath ,
const KIID_PATH & aClipPath ,
bool aForceKeepAnnotations )
{
for ( SCH_ITEM * item : aSheet - > GetScreen ( ) - > Items ( ) )
KIID_PATH clipItemPath = aClipPath ;
clipItemPath . push_back ( aSymbol - > m_Uuid ) ;
wxString reference , value , footprint ;
int unit ;
if ( m_clipboardSymbolInstances . count ( clipItemPath ) > 0 )
{
if ( item - > Type ( ) = = SCH_COMPONENT_T )
{
SCH_COMPONENT * symbol = static_cast < SCH_COMPONENT * > ( item ) ;
SYMBOL_INSTANCE_REFERENCE instance = m_clipboardSymbolInstances . at ( clipItemPath ) ;
KIID_PATH clipItemPath = aClipPath ;
clipItemPath . push_back ( symbol - > m_Uuid ) ;
unit = instance . m_Unit ;
reference = instance . m_Reference ;
value = instance . m_Value ;
footprint = instance . m_Footprint ;
}
else
{
// Pasted from notepad or an older instance of eeschema.
// Use the values in the fields instead
reference = aSymbol - > GetField ( REFERENCE_FIELD ) - > GetText ( ) ;
value = aSymbol - > GetField ( VALUE_FIELD ) - > GetText ( ) ;
footprint = aSymbol - > GetField ( FOOTPRINT_FIELD ) - > GetText ( ) ;
unit = aSymbol - > GetUnit ( ) ;
}
// SCH_REFERENCE_LIST doesn't include the root sheet in the path
clipItemPath . erase ( clipItemPath . begin ( ) ) ;
if ( aForceKeepAnnotations & & ! reference . IsEmpty ( ) )
{
aSymbol - > SetRef ( & aPastePath , reference ) ;
aSymbol - > SetValue ( & aPastePath , value ) ;
aSymbol - > SetFootprint ( & aPastePath , footprint ) ;
}
else
{
aSymbol - > ClearAnnotation ( & aPastePath ) ;
}
int ii = m_supplementaryClipboardInstances . FindRefByPath ( clipItemPath . AsString ( ) ) ;
// We might clear annotations but always leave the original unit number from the paste
aSymbol - > SetUnitSelection ( & aPastePath , unit ) ;
aSymbol - > SetUnit ( unit ) ;
}
if ( ii > = 0 )
{
SCH_REFERENCE instance = m_supplementaryClipboardInstances [ ii ] ;
symbol - > SetUnitSelection ( & aPastePath , instance . GetUnit ( ) ) ;
symbol - > SetUnit ( instance . GetUnit ( ) ) ;
SCH_SHEET_PATH SCH_EDITOR_CONTROL : : updatePastedSheet ( const SCH_SHEET_PATH & aPastePath ,
const KIID_PATH & aClipPath , SCH_SHEET * aSheet ,
bool aForceKeepAnnotations ,
SCH_SHEET_LIST * aPastedSheetsSoFar ,
SCH_REFERENCE_LIST * aPastedSymbolsSoFar )
{
SCH_SHEET_PATH sheetPath = aPastePath ;
sheetPath . push_back ( aSheet ) ;
if ( aForceKeepAnnotations )
{
symbol - > SetRef ( & aPastePath , instance . GetRef ( ) ) ;
symbol - > SetValue ( & aPastePath , instance . GetValue ( ) ) ;
symbol - > SetFootprint ( & aPastePath , instance . GetFootprint ( ) ) ;
}
else
{
symbol - > ClearAnnotation ( & aPastePath ) ;
}
}
else
{
symbol - > ClearAnnotation ( & aPastePath ) ;
}
aSheet - > AddInstance ( sheetPath . Path ( ) ) ;
wxString pageNum ;
if ( m_clipboardSheetInstances . count ( aClipPath ) > 0 )
pageNum = m_clipboardSheetInstances . at ( aClipPath ) . m_PageNumber ;
else
pageNum = wxString : : Format ( " %d " , static_cast < int > ( aPastedSheetsSoFar - > size ( ) ) ) ;
aSheet - > SetPageNumber ( sheetPath , pageNum ) ;
aPastedSheetsSoFar - > push_back ( sheetPath ) ;
if ( aSheet - > GetScreen ( ) = = nullptr )
return sheetPath ; // We can only really set the page number but not load any items
for ( SCH_ITEM * item : aSheet - > GetScreen ( ) - > Items ( ) )
{
if ( item - > Type ( ) = = SCH_COMPONENT_T )
{
SCH_COMPONENT * symbol = static_cast < SCH_COMPONENT * > ( item ) ;
updatePastedSymbol ( symbol , aSheet - > GetScreen ( ) , sheetPath , aClipPath ,
aForceKeepAnnotations ) ;
}
else if ( item - > Type ( ) = = SCH_SHEET_T )
{
SCH_SHEET * sheet = static_cast < SCH_SHEET * > ( item ) ;
SCH_SHEET_PATH pastePath = aPastePath ;
pastePath . push_back ( sheet ) ;
SCH_SHEET * subsheet = static_cast < SCH_SHEET * > ( item ) ;
KIID_PATH clipPath = aClipPath ;
clipPath . push_back ( sheet - > m_Uuid ) ;
KIID_PATH newClipPath = aClipPath ;
newClipPath . push_back ( subsheet - > m_Uuid ) ;
updatePastedSheet ( sheetPath , newClipPath , subsheet , aForceKeepAnnotations ,
aPastedSheetsSoFar , aPastedSymbolsSoFar ) ;
sheet - > AddInstance ( pastePath . Path ( ) ) ;
updatePastedInstances ( pastePath , clipPath , sheet , aForceKeepAnnotations ) ;
SCH_SHEET_PATH subSheetPath = sheetPath ;
subSheetPath . push_back ( subsheet ) ;
subSheetPath . GetSymbols ( * aPastedSymbolsSoFar ) ;
}
}
return sheetPath ;
}
void SCH_EDITOR_CONTROL : : setClipboardInstances ( const SCH_SCREEN * aPastedScreen )
{
m_clipboardSheetInstances . clear ( ) ;
for ( const SCH_SHEET_INSTANCE sheet : aPastedScreen - > GetSheetInstances ( ) )
m_clipboardSheetInstances [ sheet . m_Path ] = sheet ;
m_clipboardSymbolInstances . clear ( ) ;
for ( const SYMBOL_INSTANCE_REFERENCE symbol : aPastedScreen - > GetSymbolInstances ( ) )
m_clipboardSymbolInstances [ symbol . m_Path ] = symbol ;
}
@ -1396,6 +1452,9 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
bool forceKeepAnnotations = false ;
// Save loaded screen instances to m_clipboardSheetInstances
setClipboardInstances ( paste_screen ) ;
if ( aEvent . IsAction ( & ACTIONS : : pasteSpecial ) )
{
DIALOG_PASTE_SPECIAL dlg ( m_frame , & forceKeepAnnotations ) ;
@ -1416,10 +1475,35 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
if ( destFn . IsRelative ( ) )
destFn . MakeAbsolute ( m_frame - > Prj ( ) . GetProjectPath ( ) ) ;
// List of paths in the hierarchy that refer to the destination sheet of the paste
SCH_SHEET_LIST pasteInstances = hierarchy . FindAllSheetsForScreen ( pasteRoot . LastScreen ( ) ) ;
pasteInstances . SortByPageNumbers ( ) ;
// Build a list of screens from the current design (to avoid loading sheets that already exist)
std : : map < wxString , SCH_SCREEN * > loadedScreens ;
for ( const SCH_SHEET_PATH & item : hierarchy )
{
if ( item . LastScreen ( ) )
loadedScreens [ item . Last ( ) - > GetFileName ( ) ] = item . LastScreen ( ) ;
}
// Build symbol list for reannotation of duplicates
SCH_SHEET_LIST sheets = m_frame - > Schematic ( ) . GetSheets ( ) ;
SCH_REFERENCE_LIST existingRefs ;
sheets . GetSymbols ( existingRefs ) ;
existingRefs . SortByReferenceOnly ( ) ;
// Keep track of pasted sheets and symbols for the different
// paths to the hiearchy
std : : map < SCH_SHEET_PATH , SCH_REFERENCE_LIST > pastedSymbols ;
std : : map < SCH_SHEET_PATH , SCH_SHEET_LIST > pastedSheets ;
for ( SCH_ITEM * item : paste_screen - > Items ( ) )
{
loadedItems . push_back ( item ) ;
//@todo: we might want to sort the sheets by page number before adding to loadedItems
if ( item - > Type ( ) = = SCH_SHEET_T )
{
SCH_SHEET * sheet = static_cast < SCH_SHEET * > ( item ) ;
@ -1448,7 +1532,7 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
for ( unsigned i = 0 ; i < loadedItems . size ( ) ; + + i )
{
EDA_ITEM * item = loadedItems [ i ] ;
KIID_PATH clipPath = m_supplementaryClipboardPath ;
KIID_PATH clipPath ( wxT ( " / " ) ) ; // clipboard is at root
if ( item - > Type ( ) = = SCH_COMPONENT_T )
{
@ -1463,29 +1547,51 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
wxCHECK2 ( currentScreen , continue ) ;
auto it = currentScreen - > GetLibSymbols ( ) . find ( symbol - > GetSchSymbolLibraryName ( ) ) ;
auto end = currentScreen - > GetLibSymbols ( ) . end ( ) ;
if ( it = = end )
{
// If can't find library definition in the design, use the pasted library
it = paste_screen - > GetLibSymbols ( ) . find ( symbol - > GetSchSymbolLibraryName ( ) ) ;
end = paste_screen - > GetLibSymbols ( ) . end ( ) ;
}
LIB_PART * libPart = nullptr ;
if ( it ! = currentScreen - > GetLibSymbols ( ) . end ( ) )
symbol - > SetLibSymbol ( new LIB_PART ( * it - > second ) ) ;
if ( it ! = end )
{
libPart = new LIB_PART ( * it - > second ) ;
symbol - > SetLibSymbol ( libPart ) ;
}
if ( ! forceKeepAnnotations )
for ( SCH_SHEET_PATH & instance : pasteInstance s )
{
// clear the annotation, but preserve the selected unit
int unit = symbol - > GetUnit ( ) ;
symbol - > ClearAnnotation ( nullptr ) ;
symbol - > SetUnit ( unit ) ;
updatePastedSymbol ( symbol , paste_screen , instance , clipPath ,
forceKeepAnnotations ) ;
}
// Assign a new KIID
const_cast < KIID & > ( item - > m_Uuid ) = KIID ( ) ;
// Make sure pins get a new UUID
for ( SCH_PIN * pin : symbol - > GetPins ( ) )
const_cast < KIID & > ( pin - > m_Uuid ) = KIID ( ) ;
}
if ( item - > Type ( ) = = SCH_SHEET_T )
for ( SCH_SHEET_PATH & instance : pasteInstances )
{
// Ignore pseudo-symbols (e.g. power symbols) and symbols from a non-existant library
if ( libPart & & symbol - > GetRef ( & instance ) [ 0 ] ! = wxT ( ' # ' ) )
{
SCH_REFERENCE schReference ( symbol , libPart , instance ) ;
schReference . SetSheetNumber ( instance . GetVirtualPageNumber ( ) ) ;
pastedSymbols [ instance ] . AddItem ( schReference ) ;
}
}
}
else if ( item - > Type ( ) = = SCH_SHEET_T )
{
SCH_SHEET * sheet = ( SCH_SHEET * ) item ;
SCH_FIELD & nameField = sheet - > GetFields ( ) [ SHEETNAME ] ;
wxFileName fn = sheet - > GetFileName ( ) ;
SCH_SCREEN * existingScreen = nullptr ;
wxString baseName = nameField . GetText ( ) ;
wxString candidateName = baseName ;
wxString number ;
@ -1496,20 +1602,20 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
baseName . RemoveLast ( ) ;
}
//@todo: it might be better to just iterate through the sheet names
// in this screen instead of the whole hiearchy.
int uniquifier = std : : max ( 0 , wxAtoi ( number ) ) + 1 ;
// Ensure we have latest hierarchy, as we may have added a sheet in the previous
// iteration
hierarchy = m_frame - > Schematic ( ) . GetSheets ( ) ;
while ( hierarchy . NameExists ( candidateName ) )
candidateName = wxString : : Format ( wxT ( " %s%d " ) , baseName , uniquifier + + ) ;
nameField . SetText ( candidateName ) ;
wxFileName fn = sheet - > GetFileName ( ) ;
SCH_SCREEN * existingScreen = nullptr ;
sheet - > SetParent ( pasteRoot . Last ( ) ) ;
sheet - > SetScreen ( nullptr ) ;
sheetsPasted = true ;
if ( ! fn . IsAbsolute ( ) )
{
@ -1517,10 +1623,14 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
fn . Normalize ( wxPATH_NORM_ALL , currentSheetFileName . GetPath ( ) ) ;
}
// Try to find the screen for the pasted sheet by several means
if ( ! m_frame - > Schematic ( ) . Root ( ) . SearchHierarchy ( fn . GetFullPath ( wxPATH_UNIX ) ,
& existingScreen ) )
{
searchSupplementaryClipboard ( sheet - > GetFileName ( ) , & existingScreen ) ;
if ( loadedScreens . count ( sheet - > GetFileName ( ) ) > 0 )
existingScreen = loadedScreens . at ( sheet - > GetFileName ( ) ) ;
else
searchSupplementaryClipboard ( sheet - > GetFileName ( ) , & existingScreen ) ;
}
if ( existingScreen )
@ -1533,34 +1643,34 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
m_frame - > InitSheet ( sheet , sheet - > GetFileName ( ) ) ;
}
sheetsPasted = true ;
// Push it to the clipboard path while it still has its old KIID
clipPath . push_back ( sheet - > m_Uuid ) ;
}
// Everything gets a new KIID
const_cast < KIID & > ( item - > m_Uuid ) = KIID ( ) ;
// Once we have our new KIID we can update all pasted instances. This will either
// reset the annotations or copy "kept" annotations from the supplementary clipboard.
if ( item - > Type ( ) = = SCH_SHEET_T )
{
SCH_SHEET * sheet = ( SCH_SHEET * ) item ;
SCH_SHEET_PATH pastePath = pasteRoot ;
pastePath . push_back ( sheet ) ;
int page = 1 ;
wxString pageNum = wxString : : Format ( " %d " , page ) ;
while ( hierarchy . PageNumberExists ( pageNum ) )
pageNum = wxString : : Format ( " %d " , + + page ) ;
sheet - > AddInstance ( pastePath . Path ( ) ) ;
sheet - > SetPageNumber ( pastePath , pageNum ) ;
updatePastedInstances ( pastePath , clipPath , sheet , forceKeepAnnotations ) ;
// Assign a new KIID to the pasted sheet
const_cast < KIID & > ( sheet - > m_Uuid ) = KIID ( ) ;
// Make sure pins get a new UUID
for ( SCH_SHEET_PIN * pin : sheet - > GetPins ( ) )
const_cast < KIID & > ( pin - > m_Uuid ) = KIID ( ) ;
// Once we have our new KIID we can update all pasted instances. This will either
// reset the annotations or copy "kept" annotations from the supplementary clipboard.
for ( SCH_SHEET_PATH & instance : pasteInstances )
{
SCH_SHEET_PATH sheetPath = updatePastedSheet ( instance , clipPath , sheet ,
forceKeepAnnotations ,
& pastedSheets [ instance ] ,
& pastedSymbols [ instance ] ) ;
sheetPath . GetSymbols ( pastedSymbols [ instance ] ) ;
}
}
else
{
// Everything gets a new KIID
const_cast < KIID & > ( item - > m_Uuid ) = KIID ( ) ;
}
item - > SetFlags ( IS_NEW | IS_PASTED | IS_MOVED ) ;
@ -1573,8 +1683,29 @@ int SCH_EDITOR_CONTROL::Paste( const TOOL_EVENT& aEvent )
getView ( ) - > Hide ( item , true ) ;
}
pasteInstances . SortByPageNumbers ( ) ;
m_frame - > GetCurrentSheet ( ) . UpdateAllScreenReferences ( ) ;
if ( sheetsPasted )
{
// Update page numbers: Find next free numeric page number
for ( SCH_SHEET_PATH & instance : pasteInstances )
{
pastedSheets [ instance ] . SortByPageNumbers ( ) ;
for ( SCH_SHEET_PATH & pastedSheet : pastedSheets [ instance ] )
{
int page = 1 ;
wxString pageNum = wxString : : Format ( " %d " , page ) ;
while ( hierarchy . PageNumberExists ( pageNum ) )
pageNum = wxString : : Format ( " %d " , + + page ) ;
pastedSheet . SetPageNumber ( pageNum ) ;
hierarchy . push_back ( pastedSheet ) ;
}
}
m_frame - > SetSheetNumberAndCount ( ) ;
m_frame - > UpdateHierarchyNavigator ( ) ;
}