Tighten lifecycle management of parent group pointers.

Also adds some debugging to try to catch dangling pointers.

Also adds a cache for group bounding boxes (which will be expensive
to calculate for large groups).

Fixes https://gitlab.com/kicad/code/kicad/issues/12875
This commit is contained in:
Jeff Young 2022-11-11 17:09:25 +00:00
parent 78b0c29875
commit 03ba14c6d3
34 changed files with 218 additions and 129 deletions

View File

@ -66,6 +66,8 @@ public:
{
}
~BOARD_ITEM();
void SetParentGroup( PCB_GROUP* aGroup ) { m_group = aGroup; }
PCB_GROUP* GetParentGroup() const { return m_group; }
@ -229,7 +231,7 @@ public:
*
* @param aImage the item image which contains data to swap.
*/
virtual void SwapData( BOARD_ITEM* aImage );
void SwapItemData( BOARD_ITEM* aImage );
/**
* Test to see if this object is on the given layer.
@ -321,6 +323,8 @@ protected:
*/
virtual wxString layerMaskDescribe() const;
virtual void swapData( BOARD_ITEM* aImage );
protected:
PCB_LAYER_ID m_layer;
bool m_isKnockout;

View File

@ -145,9 +145,6 @@ public:
*/
PCB_GROUP* DeepDuplicate() const;
///< @copydoc BOARD_ITEM::SwapData
void SwapData( BOARD_ITEM* aImage ) override;
///< @copydoc BOARD_ITEM::IsOnLayer
bool IsOnLayer( PCB_LAYER_ID aLayer ) const override;
@ -221,6 +218,10 @@ public:
*/
void RunOnDescendants( const std::function<void( BOARD_ITEM* )>& aFunction ) const;
protected:
///< @copydoc BOARD_ITEM::swapData
void swapData( BOARD_ITEM* aImage ) override;
private:
std::unordered_set<BOARD_ITEM*> m_items; // Members of the group
wxString m_name; // Optional group name

View File

@ -120,6 +120,13 @@ BOARD::BOARD() :
BOARD::~BOARD()
{
// Untangle group parents before doing any deleting
for( PCB_GROUP* group : m_groups )
{
for( BOARD_ITEM* item : group->GetItems() )
item->SetParentGroup( nullptr );
}
// Clean up the owned elements
DeleteMARKERs();
@ -219,6 +226,7 @@ void BOARD::IncrementTimeStamp()
{
std::unique_lock<std::mutex> cacheLock( m_CachesMutex );
m_IntersectsAreaCache.clear();
m_EnclosedByAreaCache.clear();
m_IntersectsCourtyardCache.clear();
@ -233,6 +241,7 @@ void BOARD::IncrementTimeStamp()
m_CopperZoneRTreeCache.clear();
m_CopperItemRTreeCache = std::make_unique<DRC_RTREE>();
m_ZoneBBoxCache.clear();
m_GroupBBoxCache.clear();
}
}
@ -1690,16 +1699,6 @@ void BOARD::GetSortedPadListByXthenYCoord( std::vector<PAD*>& aVector, int aNetC
}
void BOARD::PadDelete( PAD* aPad )
{
GetConnectivity()->Remove( aPad );
InvokeListeners( &BOARD_LISTENER::OnBoardItemRemoved, *this, aPad );
aPad->DeleteStructure();
}
std::tuple<int, double, double> BOARD::GetTrackLength( const PCB_TRACK& aTrack ) const
{
int count = 0;

View File

@ -1003,14 +1003,6 @@ public:
*/
PAD* GetPad( std::vector<PAD*>& aPadList, const VECTOR2I& aPosition, LSET aLayerMask ) const;
/**
* Delete a given pad from the BOARD by removing it from its footprint and from the
* m_NetInfo. Makes no UI calls.
*
* @param aPad is the pad to delete.
*/
void PadDelete( PAD* aPad );
/**
* First empties then fills the vector with all pads and sorts them by increasing x
* coordinate, and for increasing y coordinate for same values of x coordinates. The vector
@ -1151,6 +1143,7 @@ public:
std::unordered_map<ZONE*, std::unique_ptr<DRC_RTREE>> m_CopperZoneRTreeCache;
std::unique_ptr<DRC_RTREE> m_CopperItemRTreeCache;
mutable std::unordered_map<const ZONE*, BOX2I> m_ZoneBBoxCache;
mutable std::unordered_map<const PCB_GROUP*, BOX2I> m_GroupBBoxCache;
// ------------ DRC caches -------------
std::vector<ZONE*> m_DRCZones;

View File

@ -309,6 +309,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
itemsDeselected = true;
}
if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
parentGroup->RemoveItem( boardItem );
if( autofillZones )
dirtyIntersectingZones( boardItem );
@ -339,9 +342,6 @@ void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
break;
}
if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
parentGroup->RemoveItem( boardItem );
if( view )
view->Remove( boardItem );
@ -649,7 +649,7 @@ void BOARD_COMMIT::Revert()
view->Remove( item );
connectivity->Remove( item );
item->SwapData( copy );
item->SwapItemData( copy );
view->Add( item );
connectivity->Add( item );

View File

@ -34,6 +34,12 @@
#include <pcb_group.h>
BOARD_ITEM::~BOARD_ITEM()
{
wxASSERT( m_group == nullptr );
}
const BOARD* BOARD_ITEM::GetBoard() const
{
if( Type() == PCB_T )
@ -152,11 +158,32 @@ void BOARD_ITEM::DeleteStructure()
}
void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
void BOARD_ITEM::swapData( BOARD_ITEM* aImage )
{
}
void BOARD_ITEM::SwapItemData( BOARD_ITEM* aImage )
{
if( aImage == nullptr )
return;
wxASSERT( Type() == aImage->Type() );
wxASSERT( m_Uuid == aImage->m_Uuid );
EDA_ITEM* parent = GetParent();
PCB_GROUP* group = GetParentGroup();
SetParentGroup( nullptr );
aImage->SetParentGroup( nullptr );
swapData( aImage );
// Restore pointers to be sure they are not broken
SetParent( parent );
SetParentGroup( group );
}
BOARD_ITEM* BOARD_ITEM::Duplicate() const
{
BOARD_ITEM* dupe = static_cast<BOARD_ITEM*>( Clone() );

View File

@ -45,8 +45,6 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
// Save initial zones configuration, for undo/redo, before adding new zone
// note the net name and the layer can be changed, so we must save all zones
deletedList.ClearListAndDeleteItems();
pickedList.ClearListAndDeleteItems();
SaveCopyOfZones( pickedList, GetBoard() );
if( aZone->GetIsRuleArea() )
@ -69,8 +67,8 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
if( dialogResult == wxID_CANCEL )
{
deletedList.ClearListAndDeleteItems();
pickedList.ClearListAndDeleteItems();
ClearListAndDeleteItems( &deletedList );
ClearListAndDeleteItems( &pickedList );
return;
}

View File

@ -196,6 +196,13 @@ FOOTPRINT::FOOTPRINT( FOOTPRINT&& aFootprint ) :
FOOTPRINT::~FOOTPRINT()
{
// Untangle group parents before doing any deleting
for( PCB_GROUP* group : m_fp_groups )
{
for( BOARD_ITEM* item : group->GetItems() )
item->SetParentGroup( nullptr );
}
// Clean up the owned elements
delete m_reference;
delete m_value;
@ -2573,7 +2580,7 @@ void FOOTPRINT::CheckNetTiePadGroups( const std::function<void( const wxString&
}
void FOOTPRINT::SwapData( BOARD_ITEM* aImage )
void FOOTPRINT::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == PCB_FOOTPRINT_T );

View File

@ -757,7 +757,9 @@ public:
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
#if defined(DEBUG)
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
struct cmp_drawings
{
@ -774,10 +776,8 @@ public:
bool operator()( const FP_ZONE* aFirst, const FP_ZONE* aSecond ) const;
};
#if defined(DEBUG)
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
private:
DRAWINGS m_drawings; // BOARD_ITEMs for drawings on the board, owned by pointer.

View File

@ -1541,7 +1541,7 @@ void PAD::ImportSettingsFrom( const PAD& aMasterPad )
}
void PAD::SwapData( BOARD_ITEM* aImage )
void PAD::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_PAD_T );

View File

@ -716,8 +716,6 @@ public:
virtual const BOX2I ViewBBox() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
void ClearZoneConnectionCache()
{
for( size_t ii = 0; ii < arrayDim( m_zoneLayerConnections ); ++ii )
@ -733,6 +731,8 @@ public:
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
private:
void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError,

View File

@ -205,6 +205,8 @@ public:
*/
void ClearUndoORRedoList( UNDO_REDO_LIST whichList, int aItemCount = -1 ) override;
void ClearListAndDeleteItems( PICKED_ITEMS_LIST* aList );
/**
* Return the absolute path to the design rules file for the currently-loaded board.
*

View File

@ -94,7 +94,7 @@ EDA_ITEM* PCB_BITMAP::Clone() const
}
void PCB_BITMAP::SwapData( BOARD_ITEM* aItem )
void PCB_BITMAP::swapData( BOARD_ITEM* aItem )
{
wxCHECK_RET( aItem->Type() == PCB_BITMAP_T,
wxString::Format( wxT( "PCB_BITMAP object cannot swap data with %s object." ),

View File

@ -85,8 +85,6 @@ public:
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
void SwapData( BOARD_ITEM* aItem ) override;
//void Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& aOffset ) override;
/// @copydoc VIEW_ITEM::ViewGetLayers()
@ -128,6 +126,9 @@ public:
void Show( int nestLevel, std::ostream& os ) const override;
#endif
protected:
void swapData( BOARD_ITEM* aItem ) override;
private:
VECTOR2I m_pos; // XY coordinates of center of the bitmap
BITMAP_BASE* m_image; // the BITMAP_BASE item

View File

@ -560,7 +560,7 @@ EDA_ITEM* PCB_DIM_ALIGNED::Clone() const
}
void PCB_DIM_ALIGNED::SwapData( BOARD_ITEM* aImage )
void PCB_DIM_ALIGNED::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == Type() );
@ -752,7 +752,7 @@ EDA_ITEM* PCB_DIM_ORTHOGONAL::Clone() const
}
void PCB_DIM_ORTHOGONAL::SwapData( BOARD_ITEM* aImage )
void PCB_DIM_ORTHOGONAL::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == Type() );
@ -969,7 +969,7 @@ EDA_ITEM* PCB_DIM_LEADER::Clone() const
}
void PCB_DIM_LEADER::SwapData( BOARD_ITEM* aImage )
void PCB_DIM_LEADER::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == Type() );
@ -1112,7 +1112,7 @@ EDA_ITEM* PCB_DIM_RADIAL::Clone() const
}
void PCB_DIM_RADIAL::SwapData( BOARD_ITEM* aImage )
void PCB_DIM_RADIAL::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == Type() );
@ -1240,7 +1240,7 @@ EDA_ITEM* PCB_DIM_CENTER::Clone() const
}
void PCB_DIM_CENTER::SwapData( BOARD_ITEM* aImage )
void PCB_DIM_CENTER::swapData( BOARD_ITEM* aImage )
{
wxASSERT( aImage->Type() == Type() );

View File

@ -358,8 +358,6 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
void Mirror( const VECTOR2I& axis_pos, bool aMirrorLeftRight = false ) override;
BITMAPS GetMenuImage() const override;
@ -406,6 +404,8 @@ public:
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
void updateGeometry() override;
void updateText() override;
@ -445,8 +445,6 @@ public:
EDA_ITEM* Clone() const override;
void SwapData( BOARD_ITEM* aImage ) override;
BITMAPS GetMenuImage() const override;
/**
@ -464,6 +462,8 @@ public:
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
protected:
void swapData( BOARD_ITEM* aImage ) override;
void updateGeometry() override;
void updateText() override;
@ -508,8 +508,6 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
void SetLeaderLength( int aLength ) { m_leaderLength = aLength; }
int GetLeaderLength() const { return m_leaderLength; }
@ -524,6 +522,8 @@ public:
}
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
void updateText() override;
void updateGeometry() override;
@ -559,8 +559,6 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
BITMAPS GetMenuImage() const override;
wxString GetClass() const override
@ -574,6 +572,8 @@ public:
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
void updateGeometry() override;
private:
@ -600,8 +600,6 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
BITMAPS GetMenuImage() const override;
wxString GetClass() const override
@ -614,6 +612,8 @@ public:
const BOX2I ViewBBox() const override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
void updateGeometry() override;
};

View File

@ -208,7 +208,7 @@ PCB_GROUP* PCB_GROUP::DeepDuplicate() const
}
void PCB_GROUP::SwapData( BOARD_ITEM* aImage )
void PCB_GROUP::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_GROUP_T );
@ -234,16 +234,41 @@ const BOX2I PCB_GROUP::GetBoundingBox() const
{
BOX2I bbox;
for( BOARD_ITEM* item : m_items )
auto calcBBox =
[this]()
{
BOX2I box;
for( BOARD_ITEM* item : m_items )
{
if( item->Type() == PCB_FOOTPRINT_T )
box.Merge( static_cast<FOOTPRINT*>( item )->GetBoundingBox( true, false ) );
else
box.Merge( item->GetBoundingBox() );
}
box.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
return box;
};
if( const BOARD* board = GetBoard() )
{
if( item->Type() == PCB_FOOTPRINT_T )
bbox.Merge( static_cast<FOOTPRINT*>( item )->GetBoundingBox( true, false ) );
else
bbox.Merge( item->GetBoundingBox() );
std::unordered_map<const PCB_GROUP*, BOX2I>& cache = board->m_GroupBBoxCache;
auto cacheIter = cache.find( this );
if( cacheIter != cache.end() )
return cacheIter->second;
bbox = calcBBox();
std::unique_lock<std::mutex> cacheLock( const_cast<BOARD*>( board )->m_CachesMutex );
cache[ this ] = bbox;
return bbox;
}
bbox.Inflate( pcbIUScale.mmToIU( 0.25 ) ); // Give a min size to the bbox
return bbox;
}

View File

@ -347,7 +347,7 @@ std::shared_ptr<SHAPE> PCB_SHAPE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHI
}
void PCB_SHAPE::SwapData( BOARD_ITEM* aImage )
void PCB_SHAPE::swapData( BOARD_ITEM* aImage )
{
PCB_SHAPE* image = dynamic_cast<PCB_SHAPE*>( aImage );
assert( image );

View File

@ -145,18 +145,18 @@ public:
///< @copydoc VIEW_ITEM::ViewGetLOD
double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
struct cmp_drawings
{
bool operator()( const BOARD_ITEM* aFirst, const BOARD_ITEM* aSecond ) const;
};
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
EDA_ANGLE getParentOrientation() const override;
VECTOR2I getParentPosition() const override;
};

View File

@ -138,7 +138,7 @@ EDA_ITEM* PCB_TARGET::Clone() const
}
void PCB_TARGET::SwapData( BOARD_ITEM* aImage )
void PCB_TARGET::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_TARGET_T );

View File

@ -92,8 +92,6 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
/**
@ -116,6 +114,9 @@ public:
void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
private:
int m_shape; // bit 0 : 0 = draw +, 1 = draw X
int m_size;

View File

@ -272,7 +272,7 @@ EDA_ITEM* PCB_TEXT::Clone() const
}
void PCB_TEXT::SwapData( BOARD_ITEM* aImage )
void PCB_TEXT::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_TEXT_T );

View File

@ -147,13 +147,13 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
#if defined(DEBUG)
virtual void Show( int nestLevel, std::ostream& os ) const override { ShowDummy( os ); }
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
int getKnockoutMargin() const;
};

View File

@ -430,7 +430,7 @@ EDA_ITEM* PCB_TEXTBOX::Clone() const
}
void PCB_TEXTBOX::SwapData( BOARD_ITEM* aImage )
void PCB_TEXTBOX::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_TEXTBOX_T );

View File

@ -135,7 +135,8 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
};
#endif // #define PCB_TEXTBOX_H

View File

@ -1074,21 +1074,21 @@ BITMAPS PCB_TRACK::GetMenuImage() const
return BITMAPS::add_tracks;
}
void PCB_TRACK::SwapData( BOARD_ITEM* aImage )
void PCB_TRACK::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_TRACE_T );
std::swap( *((PCB_TRACK*) this), *((PCB_TRACK*) aImage) );
}
void PCB_ARC::SwapData( BOARD_ITEM* aImage )
void PCB_ARC::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_ARC_T );
std::swap( *this, *static_cast<PCB_ARC*>( aImage ) );
}
void PCB_VIA::SwapData( BOARD_ITEM* aImage )
void PCB_VIA::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_VIA_T );

View File

@ -210,8 +210,6 @@ public:
const BOX2I ViewBBox() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
/**
* @return true because a track or a via is always on a copper layer.
*/
@ -266,6 +264,8 @@ public:
#endif
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
void GetMsgPanelInfoBase_Common( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) const;
protected:
@ -349,7 +349,8 @@ public:
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
private:
VECTOR2I m_Mid; ///< Arc mid point, halfway between start and end
@ -534,8 +535,6 @@ public:
*/
bool IsDrillDefault() const { return m_drill <= 0; }
void SwapData( BOARD_ITEM* aImage ) override;
// @copydoc BOARD_ITEM::GetEffectiveShape
std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
@ -552,6 +551,8 @@ public:
}
protected:
void swapData( BOARD_ITEM* aImage ) override;
wxString layerMaskDescribe() const override;
private:

View File

@ -1001,7 +1001,7 @@ int BOARD_EDITOR_CONTROL::PlaceFootprint( const TOOL_EVENT& aEvent )
if( undo )
{
m_frame->PutDataInPreviousState( undo );
undo->ClearListAndDeleteItems();
m_frame->ClearListAndDeleteItems( undo );
delete undo;
}
}

View File

@ -681,26 +681,36 @@ int EDIT_TOOL::DragArcTrack( const TOOL_EVENT& aEvent )
if( aTrack->GetLength() <= aMaxLengthIU )
{
aTrack->SetParentGroup( nullptr );
delete aTrack;
delete aTrackCopy;
aTrack = nullptr;
aTrackCopy->SetParentGroup( nullptr );
delete aTrackCopy;
aTrackCopy = nullptr;
return false;
}
else
{
m_commit->Add( aTrack );
aTrackCopy->SetParentGroup( nullptr );
delete aTrackCopy;
aTrackCopy = nullptr;
return true;
}
}
else if( aTrack->GetLength() <= aMaxLengthIU )
{
aTrack->SwapData( aTrackCopy ); //restore the original before notifying COMMIT
aTrack->SwapItemData( aTrackCopy ); //restore the original before notifying COMMIT
m_commit->Remove( aTrack );
aTrackCopy->SetParentGroup( nullptr );
delete aTrackCopy;
aTrackCopy = nullptr;
return false;
}
else

View File

@ -452,6 +452,8 @@ int EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, bool aPickReference )
grid.SetSnap( !evt->Modifier( MD_SHIFT ) );
grid.SetUseGrid( getView()->GetGAL()->GetGridSnapping() && !evt->DisableGridSnapping() );
board->m_GroupBBoxCache.clear();
if( evt->IsMotion() || evt->IsDrag( BUT_LEFT ) )
eatFirstMouseUp = false;

View File

@ -848,6 +848,14 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
FOOTPRINT* editorFootprint = board()->GetFirstFootprint();
std::vector<BOARD_ITEM*> pastedItems;
for( PCB_GROUP* group : clipBoard->Groups() )
{
group->SetParent( nullptr );
pastedItems.push_back( group );
}
clipBoard->Groups().clear();
for( FOOTPRINT* clipFootprint : clipBoard->Footprints() )
pasteFootprintItemsToFootprintEditor( clipFootprint, board(), pastedItems );
@ -856,44 +864,61 @@ int PCB_CONTROL::Paste( const TOOL_EVENT& aEvent )
if( clipDrawItem->Type() == PCB_SHAPE_T )
{
PCB_SHAPE* clipShape = static_cast<PCB_SHAPE*>( clipDrawItem );
PCB_GROUP* parentGroup = clipDrawItem->GetParentGroup();
if( parentGroup )
parentGroup->RemoveItem( clipDrawItem );
// Convert to PCB_FP_SHAPE_T
FP_SHAPE* pastedShape = new FP_SHAPE( editorFootprint );
static_cast<PCB_SHAPE*>( pastedShape )->SwapData( clipShape );
static_cast<PCB_SHAPE*>( pastedShape )->SwapItemData( clipShape );
pastedShape->SetLocalCoord();
// Replace parent nuked by above call to SwapData()
pastedShape->SetParent( editorFootprint );
if( parentGroup )
parentGroup->AddItem( pastedShape );
pastedItems.push_back( pastedShape );
}
else if( clipDrawItem->Type() == PCB_TEXT_T )
{
PCB_TEXT* clipTextItem = static_cast<PCB_TEXT*>( clipDrawItem );
PCB_TEXT* clipTextItem = static_cast<PCB_TEXT*>( clipDrawItem );
PCB_GROUP* parentGroup = clipDrawItem->GetParentGroup();
if( parentGroup )
parentGroup->RemoveItem( clipDrawItem );
// Convert to PCB_FP_TEXT_T
FP_TEXT* pastedTextItem = new FP_TEXT( editorFootprint );
static_cast<EDA_TEXT*>( pastedTextItem )->SwapText( *clipTextItem );
static_cast<EDA_TEXT*>( pastedTextItem )->SwapAttributes( *clipTextItem );
pastedTextItem->SetParent( editorFootprint );
if( parentGroup )
parentGroup->AddItem( pastedTextItem );
pastedItems.push_back( pastedTextItem );
}
else if( clipDrawItem->Type() == PCB_TEXTBOX_T )
{
PCB_TEXTBOX* clipTextBox = static_cast<PCB_TEXTBOX*>( clipDrawItem );
PCB_GROUP* parentGroup = clipDrawItem->GetParentGroup();
if( parentGroup )
parentGroup->RemoveItem( clipDrawItem );
// Convert to PCB_FP_TEXTBOX_T
FP_TEXTBOX* pastedTextBox = new FP_TEXTBOX( editorFootprint );
// Handle shape data
static_cast<PCB_SHAPE*>( pastedTextBox )->SwapData( clipTextBox );
static_cast<PCB_SHAPE*>( pastedTextBox )->SwapItemData( clipTextBox );
pastedTextBox->SetLocalCoord();
// Handle text data
static_cast<EDA_TEXT*>( pastedTextBox )->SwapText( *clipTextBox );
static_cast<EDA_TEXT*>( pastedTextBox )->SwapAttributes( *clipTextBox );
pastedTextBox->SetParent( editorFootprint );
if( parentGroup )
parentGroup->AddItem( pastedTextBox );
pastedItems.push_back( pastedTextBox );
}
}

View File

@ -4,7 +4,7 @@
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2016 CERN
* Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2012-2022 KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software; you can redistribute it and/or
@ -154,28 +154,6 @@ static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
}
static void SwapItemData( BOARD_ITEM* aItem, BOARD_ITEM* aImage )
{
if( aImage == nullptr )
return;
wxASSERT( aItem->Type() == aImage->Type() );
// Remark: to create images of edited items to undo, we are using Clone method
// which does not do a deep copy.
// So we have to use the current values of these parameters.
wxASSERT( aItem->m_Uuid == aImage->m_Uuid );
EDA_ITEM* parent = aItem->GetParent();
aItem->SwapData( aImage );
// Restore pointers to be sure they are not broken
aItem->SetParent( parent );
}
void PCB_BASE_EDIT_FRAME::saveCopyInUndoList( PICKED_ITEMS_LIST* commandToUndo,
const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType )
@ -469,11 +447,11 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList )
BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
// Remove all pads/drawings/texts, as they become invalid
// for the VIEW after SwapData() called for footprints
// for the VIEW after SwapItemData() called for footprints
view->Remove( item );
connectivity->Remove( item );
SwapItemData( item, image );
item->SwapItemData( image );
if( item->Type() == PCB_GROUP_T )
{
@ -594,19 +572,32 @@ void PCB_BASE_EDIT_FRAME::ClearUndoORRedoList( UNDO_REDO_LIST whichList, int aIt
PICKED_ITEMS_LIST* curr_cmd = list.m_CommandsList[0];
list.m_CommandsList.erase( list.m_CommandsList.begin() );
curr_cmd->ClearListAndDeleteItems();
ClearListAndDeleteItems( curr_cmd );
delete curr_cmd; // Delete command
}
}
void PCB_BASE_EDIT_FRAME::ClearListAndDeleteItems( PICKED_ITEMS_LIST* aList )
{
for( size_t ii = 0; ii < aList->GetCount(); ++ii )
{
if( BOARD_ITEM* item = static_cast<BOARD_ITEM*>( aList->GetPickedItem( ii ) ) )
item->SetParentGroup( nullptr );
if( BOARD_ITEM* link = static_cast<BOARD_ITEM*>( aList->GetPickedItemLink( ii ) ) )
link->SetParentGroup( nullptr );
}
aList->ClearListAndDeleteItems();
}
void PCB_BASE_EDIT_FRAME::RollbackFromUndo()
{
PICKED_ITEMS_LIST* undo = PopCommandFromUndoList();
PutDataInPreviousState( undo );
undo->ClearListAndDeleteItems();
ClearListAndDeleteItems( undo );
delete undo;
GetCanvas()->Refresh();

View File

@ -972,7 +972,7 @@ BITMAPS ZONE::GetMenuImage() const
}
void ZONE::SwapData( BOARD_ITEM* aImage )
void ZONE::swapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_ZONE_T || aImage->Type() == PCB_FP_ZONE_T );

View File

@ -781,7 +781,8 @@ public:
#endif
virtual void SwapData( BOARD_ITEM* aImage ) override;
protected:
virtual void swapData( BOARD_ITEM* aImage ) override;
protected:
SHAPE_POLY_SET* m_Poly; ///< Outline of the zone.