Add system for property change notifications
Use this to sync symbol field edits that are synced by the dialog Fixes https://gitlab.com/kicad/code/kicad/-/issues/15697
This commit is contained in:
parent
a817eaa67f
commit
9c1a160fcd
|
@ -19,6 +19,7 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <inspectable.h>
|
||||
#include <properties/property_mgr.h>
|
||||
#include <properties/property.h>
|
||||
|
||||
|
@ -427,3 +428,33 @@ PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses()
|
|||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::PropertyChanged( INSPECTABLE* aObject, PROPERTY_BASE* aProperty )
|
||||
{
|
||||
auto listeners = m_listeners.find( TYPE_HASH( *aObject ) );
|
||||
|
||||
if( listeners == m_listeners.end() )
|
||||
return;
|
||||
|
||||
for( const PROPERTY_LISTENER& listener : listeners->second )
|
||||
listener( aObject, aProperty, m_managedCommit );
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_COMMIT_HANDLER::PROPERTY_COMMIT_HANDLER( COMMIT* aCommit )
|
||||
{
|
||||
wxCHECK2_MSG( PROPERTY_MANAGER::Instance().m_managedCommit == nullptr,
|
||||
return, "Can't have more than one managed commit at a time!" );
|
||||
|
||||
PROPERTY_MANAGER::Instance().m_managedCommit = aCommit;
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_COMMIT_HANDLER::~PROPERTY_COMMIT_HANDLER()
|
||||
{
|
||||
wxASSERT_MSG( PROPERTY_MANAGER::Instance().m_managedCommit != nullptr,
|
||||
"Something went wrong: m_managedCommit already null!" );
|
||||
|
||||
PROPERTY_MANAGER::Instance().m_managedCommit = nullptr;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
#include <bus_alias.h>
|
||||
#include <commit.h>
|
||||
#include <connection_graph.h>
|
||||
#include <core/ignore.h>
|
||||
#include <core/kicad_algo.h>
|
||||
#include <ee_collectors.h>
|
||||
#include <erc_settings.h>
|
||||
#include <sch_marker.h>
|
||||
#include <project.h>
|
||||
|
@ -44,6 +46,75 @@ SCHEMATIC::SCHEMATIC( PROJECT* aPrj ) :
|
|||
m_connectionGraph = new CONNECTION_GRAPH( this );
|
||||
|
||||
SetProject( aPrj );
|
||||
|
||||
PROPERTY_MANAGER::Instance().RegisterListener( TYPE_HASH( SCH_FIELD ),
|
||||
[&]( INSPECTABLE* aItem, PROPERTY_BASE* aProperty, COMMIT* aCommit )
|
||||
{
|
||||
// Special case: propagate value, footprint, and datasheet fields to other units
|
||||
// of a given symbol if they aren't in the selection
|
||||
|
||||
SCH_FIELD* field = dynamic_cast<SCH_FIELD*>( aItem );
|
||||
|
||||
if( !field || !IsValid() )
|
||||
return;
|
||||
|
||||
SCH_SYMBOL* symbol = dynamic_cast<SCH_SYMBOL*>( field->GetParent() );
|
||||
|
||||
if( !symbol || aProperty->Name() != _HKI( "Text" ) )
|
||||
return;
|
||||
|
||||
// TODO(JE) This will need to get smarter to enable API access
|
||||
SCH_SHEET_PATH sheetPath = CurrentSheet();
|
||||
|
||||
wxString newValue = aItem->Get<wxString>( aProperty );
|
||||
|
||||
wxString ref = symbol->GetRef( &sheetPath );
|
||||
int unit = symbol->GetUnit();
|
||||
LIB_ID libId = symbol->GetLibId();
|
||||
|
||||
for( SCH_SHEET_PATH& sheet : GetSheets() )
|
||||
{
|
||||
std::vector<SCH_SYMBOL*> otherUnits;
|
||||
|
||||
CollectOtherUnits( ref, unit, libId, sheet, &otherUnits );
|
||||
|
||||
for( SCH_SYMBOL* otherUnit : otherUnits )
|
||||
{
|
||||
switch( field->GetId() )
|
||||
{
|
||||
case VALUE_FIELD:
|
||||
{
|
||||
if( aCommit )
|
||||
aCommit->Modify( otherUnit, sheet.LastScreen() );
|
||||
|
||||
otherUnit->SetValueFieldText( newValue );
|
||||
break;
|
||||
}
|
||||
|
||||
case FOOTPRINT_FIELD:
|
||||
{
|
||||
if( aCommit )
|
||||
aCommit->Modify( otherUnit, sheet.LastScreen() );
|
||||
|
||||
otherUnit->SetFootprintFieldText( newValue );
|
||||
break;
|
||||
}
|
||||
|
||||
case DATASHEET_FIELD:
|
||||
{
|
||||
if( aCommit )
|
||||
aCommit->Modify( otherUnit, sheet.LastScreen() );
|
||||
|
||||
otherUnit->GetField( DATASHEET_FIELD )->SetText( newValue );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -192,6 +192,8 @@ void SCH_PROPERTIES_PANEL::valueChanged( wxPropertyGridEvent& aEvent )
|
|||
SCH_COMMIT changes( m_frame );
|
||||
SCH_SCREEN* screen = m_frame->GetScreen();
|
||||
|
||||
PROPERTY_COMMIT_HANDLER handler( &changes );
|
||||
|
||||
for( EDA_ITEM* edaItem : selection )
|
||||
{
|
||||
SCH_ITEM* item = static_cast<SCH_ITEM*>( edaItem );
|
||||
|
|
|
@ -39,31 +39,41 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
bool Set( PROPERTY_BASE* aProperty, wxAny& aValue )
|
||||
bool Set( PROPERTY_BASE* aProperty, wxAny& aValue, bool aNotify = true )
|
||||
{
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
void* object = propMgr.TypeCast( this, TYPE_HASH( *this ), aProperty->OwnerHash() );
|
||||
|
||||
if( object )
|
||||
{
|
||||
aProperty->setter( object, aValue );
|
||||
|
||||
if( aNotify )
|
||||
propMgr.PropertyChanged( this, aProperty );
|
||||
}
|
||||
|
||||
return object != nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Set( PROPERTY_BASE* aProperty, T aValue )
|
||||
bool Set( PROPERTY_BASE* aProperty, T aValue, bool aNotify = true )
|
||||
{
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
void* object = propMgr.TypeCast( this, TYPE_HASH( *this ), aProperty->OwnerHash() );
|
||||
|
||||
if( object )
|
||||
{
|
||||
aProperty->set<T>( object, aValue );
|
||||
|
||||
if( aNotify )
|
||||
propMgr.PropertyChanged( this, aProperty );
|
||||
}
|
||||
|
||||
return object != nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool Set( const wxString& aProperty, T aValue )
|
||||
bool Set( const wxString& aProperty, T aValue, bool aNotify = true )
|
||||
{
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
TYPE_ID thisType = TYPE_HASH( *this );
|
||||
|
@ -75,7 +85,12 @@ public:
|
|||
object = propMgr.TypeCast( this, thisType, prop->OwnerHash() );
|
||||
|
||||
if( object )
|
||||
{
|
||||
prop->set<T>( object, aValue );
|
||||
|
||||
if( aNotify )
|
||||
propMgr.PropertyChanged( this, prop );
|
||||
}
|
||||
}
|
||||
|
||||
return object != nullptr;
|
||||
|
|
|
@ -41,6 +41,7 @@ class PROPERTY_BASE;
|
|||
class TYPE_CAST_BASE;
|
||||
class ORIGIN_TRANSFORMS;
|
||||
class INSPECTABLE;
|
||||
class COMMIT;
|
||||
|
||||
///< Unique type identifier
|
||||
using TYPE_ID = size_t;
|
||||
|
@ -56,6 +57,16 @@ using PROPERTY_FUNCTOR_MAP = PROPERTY_MAP<std::function<bool( INSPECTABLE* )>>;
|
|||
|
||||
using PROPERTY_DISPLAY_ORDER = std::map<PROPERTY_BASE*, int>;
|
||||
|
||||
using PROPERTY_LISTENER = std::function<void( INSPECTABLE*, PROPERTY_BASE*, COMMIT* )>;
|
||||
|
||||
class PROPERTY_COMMIT_HANDLER
|
||||
{
|
||||
public:
|
||||
PROPERTY_COMMIT_HANDLER( COMMIT* aCommit );
|
||||
|
||||
~PROPERTY_COMMIT_HANDLER();
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide class metadata. Each class handled by PROPERTY_MANAGER
|
||||
* needs to be described using AddProperty(), AddTypeCast() and InheritsAfter() methods.
|
||||
|
@ -249,12 +260,32 @@ public:
|
|||
|
||||
std::vector<TYPE_ID> GetMatchingClasses( PROPERTY_BASE* aProperty );
|
||||
|
||||
/**
|
||||
* Callback to alert the notification system that a property has changed
|
||||
* @param aObject is the object whose property just changed
|
||||
* @param aProperty is the property that changed
|
||||
*/
|
||||
void PropertyChanged( INSPECTABLE* aObject, PROPERTY_BASE* aProperty );
|
||||
|
||||
/**
|
||||
* Registers a listener for the given type
|
||||
* @param aType is the type to add the listener for
|
||||
* @param aListenerFunc will be called every time a property on aType is changed
|
||||
*/
|
||||
void RegisterListener( TYPE_ID aType, PROPERTY_LISTENER aListenerFunc )
|
||||
{
|
||||
m_listeners[aType].emplace_back( aListenerFunc );
|
||||
}
|
||||
|
||||
private:
|
||||
PROPERTY_MANAGER() :
|
||||
m_dirty( false )
|
||||
m_dirty( false ),
|
||||
m_managedCommit( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
friend class PROPERTY_COMMIT_HANDLER;
|
||||
|
||||
///< Structure holding type meta-data
|
||||
struct CLASS_DESC
|
||||
{
|
||||
|
@ -324,6 +355,10 @@ private:
|
|||
|
||||
/// Flag indicating that the list of properties needs to be rebuild (RebuildProperties())
|
||||
bool m_dirty;
|
||||
|
||||
std::map<TYPE_ID, std::vector<PROPERTY_LISTENER>> m_listeners;
|
||||
|
||||
COMMIT* m_managedCommit;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue