From 34ba343754cd7392cd988a1b59c8cb3c7e5e351e Mon Sep 17 00:00:00 2001 From: Marek Roszko Date: Wed, 10 May 2023 22:53:10 -0400 Subject: [PATCH] Add SCHEMATIC_LISTENER equivalent to BOARD_LISTENER --- eeschema/sch_edit_frame.cpp | 3 ++ eeschema/schematic.cpp | 43 ++++++++++++++++++++++++ eeschema/schematic.h | 62 +++++++++++++++++++++++++++++++++++ eeschema/schematic_commit.cpp | 35 ++++++++++++++++++++ 4 files changed, 143 insertions(+) diff --git a/eeschema/sch_edit_frame.cpp b/eeschema/sch_edit_frame.cpp index 5126d95c68..98881ac4aa 100644 --- a/eeschema/sch_edit_frame.cpp +++ b/eeschema/sch_edit_frame.cpp @@ -309,6 +309,9 @@ SCH_EDIT_FRAME::~SCH_EDIT_FRAME() SetScreen( nullptr ); + if( m_schematic ) + m_schematic->RemoveAllListeners(); + delete m_schematic; m_schematic = nullptr; diff --git a/eeschema/schematic.cpp b/eeschema/schematic.cpp index e6932a137f..1f0df4003f 100644 --- a/eeschema/schematic.cpp +++ b/eeschema/schematic.cpp @@ -673,3 +673,46 @@ void SCHEMATIC::FixupJunctions() } } } + + +void SCHEMATIC::OnItemsAdded( std::vector& aNewItems ) +{ + InvokeListeners( &SCHEMATIC_LISTENER::OnSchItemsAdded, *this, aNewItems ); +} + + +void SCHEMATIC::OnItemsRemoved( std::vector& aRemovedItems ) +{ + InvokeListeners( &SCHEMATIC_LISTENER::OnSchItemsRemoved, *this, aRemovedItems ); +} + + +void SCHEMATIC::AddListener( SCHEMATIC_LISTENER* aListener ) +{ + if( !alg::contains( m_listeners, aListener ) ) + m_listeners.push_back( aListener ); +} + + +void SCHEMATIC::RemoveListener( SCHEMATIC_LISTENER* aListener ) +{ + auto i = std::find( m_listeners.begin(), m_listeners.end(), aListener ); + + if( i != m_listeners.end() ) + { + std::iter_swap( i, m_listeners.end() - 1 ); + m_listeners.pop_back(); + } +} + + +void SCHEMATIC::RemoveAllListeners() +{ + m_listeners.clear(); +} + + +void SCHEMATIC::OnItemsChanged( std::vector& aItems ) +{ + InvokeListeners( &SCHEMATIC_LISTENER::OnSchItemsChanged, *this, aItems ); +} \ No newline at end of file diff --git a/eeschema/schematic.h b/eeschema/schematic.h index 66884c9169..0483ab7b7d 100644 --- a/eeschema/schematic.h +++ b/eeschema/schematic.h @@ -50,6 +50,17 @@ public: virtual PROJECT& Prj() const = 0; }; +class SCHEMATIC; + +class SCHEMATIC_LISTENER +{ +public: + virtual ~SCHEMATIC_LISTENER() {} + virtual void OnSchItemsAdded( SCHEMATIC& aSch, std::vector& aSchItem ) {} + virtual void OnSchItemsRemoved( SCHEMATIC& aSch, std::vector& aSchItem ) {} + virtual void OnSchItemsChanged( SCHEMATIC& aSch, std::vector& aSchItem ) {} +}; + /** * Holds all the data relating to one schematic. * @@ -228,6 +239,45 @@ public: */ void FixupJunctions(); + /** + * Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for + * listeners. + */ + void OnItemsAdded( std::vector& aNewItems ); + + /** + * Must be used if Remove() is used using a BULK_x REMOVE_MODE to generate a change event + * for listeners. + */ + void OnItemsRemoved( std::vector& aRemovedItems ); + + /** + * Add a listener to the schematic to receive calls whenever something on the + * schematic has been modified. The schematic does not take ownership of the + * listener object. Make sure to call RemoveListener before deleting the + * listener object. The order of listener invocations is not guaranteed. + * If the specified listener object has been added before, it will not be + * added again. + */ + void AddListener( SCHEMATIC_LISTENER* aListener ); + + /** + * Remove the specified listener. If it has not been added before, it + * will do nothing. + */ + void RemoveListener( SCHEMATIC_LISTENER* aListener ); + + /** + * Remove all listeners + */ + void RemoveAllListeners(); + + /** + * Notify the schematic and its listeners that an item on the schematic has + * been modified in some way. + */ + void OnItemsChanged( std::vector& aItems ); + #if defined(DEBUG) void Show( int nestLevel, std::ostream& os ) const override {} #endif @@ -235,6 +285,13 @@ public: private: friend class SCH_EDIT_FRAME; + template + void InvokeListeners( Func&& aFunc, Args&&... args ) + { + for( auto&& l : m_listeners ) + ( l->*aFunc )( std::forward( args )... ); + } + PROJECT* m_project; /// The top-level sheet in this schematic hierarchy (or potentially the only one) @@ -266,6 +323,11 @@ private: * Simulation operating points for text variable substitution. */ std::map m_operatingPoints; + + /** + * Currently installed listeners + */ + std::vector m_listeners; }; #endif diff --git a/eeschema/schematic_commit.cpp b/eeschema/schematic_commit.cpp index 2735f3106b..187e391da2 100644 --- a/eeschema/schematic_commit.cpp +++ b/eeschema/schematic_commit.cpp @@ -249,6 +249,11 @@ void SCHEMATIC_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags ) if( Empty() ) return; + SCHEMATIC& schematic = static_cast( m_toolMgr->GetToolHolder() )->Schematic(); + std::vector bulkAddedItems; + std::vector bulkRemovedItems; + std::vector itemsChanged; + for( COMMIT_LINE& ent : m_changes ) { int changeType = ent.m_type & CHT_TYPE; @@ -277,6 +282,8 @@ void SCHEMATIC_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags ) if( view ) view->Add( schItem ); + bulkAddedItems.push_back( schItem ); + break; } @@ -302,6 +309,8 @@ void SCHEMATIC_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags ) if( view ) view->Remove( schItem ); + bulkRemovedItems.push_back( schItem ); + if( !( changeFlags & CHT_DONE ) ) frame->GetScreen()->Remove( schItem ); @@ -321,6 +330,8 @@ void SCHEMATIC_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags ) if( view ) view->Update( schItem ); + itemsChanged.push_back( schItem ); + // if no undo entry is needed, the copy would create a memory leak if( aCommitFlags & SKIP_UNDO ) delete ent.m_copy; @@ -334,6 +345,15 @@ void SCHEMATIC_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags ) } } + if( bulkAddedItems.size() > 0 ) + schematic.OnItemsAdded( bulkAddedItems ); + + if( bulkRemovedItems.size() > 0 ) + schematic.OnItemsRemoved( bulkRemovedItems ); + + if( itemsChanged.size() > 0 ) + schematic.OnItemsChanged( itemsChanged ); + if( !( aCommitFlags & SKIP_UNDO ) && frame ) frame->SaveCopyInUndoList(undoList, UNDO_REDO::UNSPECIFIED, aCommitFlags & APPEND_UNDO ); @@ -418,6 +438,10 @@ void SCHEMATIC_COMMIT::Revert() SCHEMATIC& schematic = static_cast( m_toolMgr->GetToolHolder() )->Schematic(); + std::vector bulkAddedItems; + std::vector bulkRemovedItems; + std::vector itemsChanged; + for( auto it = m_changes.rbegin(); it != m_changes.rend(); ++it ) { COMMIT_LINE& ent = *it; @@ -435,6 +459,7 @@ void SCHEMATIC_COMMIT::Revert() view->Remove( item ); screen->Remove( item ); + bulkRemovedItems.push_back( item ); break; case CHT_REMOVE: @@ -443,6 +468,7 @@ void SCHEMATIC_COMMIT::Revert() view->Add( item ); screen->Append( item ); + bulkAddedItems.push_back( item ); break; case CHT_MODIFY: @@ -476,6 +502,15 @@ void SCHEMATIC_COMMIT::Revert() } } + if( bulkAddedItems.size() > 0 ) + schematic.OnItemsAdded( bulkAddedItems ); + + if( bulkRemovedItems.size() > 0 ) + schematic.OnItemsRemoved( bulkRemovedItems ); + + if( itemsChanged.size() > 0 ) + schematic.OnItemsChanged( itemsChanged ); + EE_SELECTION_TOOL* selTool = m_toolMgr->GetTool(); selTool->RebuildSelection();