cvpcb: Replumb the footprint association system

This is in preparation for implementing more association actions
and an undo/redo system.
This commit is contained in:
Ian McInerney 2019-07-24 22:56:17 +02:00 committed by Wayne Stambaugh
parent 72120e0a96
commit 402031244d
10 changed files with 260 additions and 107 deletions

View File

@ -40,10 +40,11 @@
#include <kicad_string.h>
#include <macros.h>
#include <auto_associate.h>
#include <cvpcb.h>
#include <cvpcb_association.h>
#include <cvpcb_mainframe.h>
#include <listboxes.h>
#include <auto_associate.h>
#define QUOTE '\''
@ -231,7 +232,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
// If the equivalence is unique, no ambiguity: use the association
if( module && equ_is_unique )
{
SetNewPkg( equivItem.m_FootprintFPID, kk );
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) );
found = true;
break;
}
@ -269,7 +270,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
if( found )
{
SetNewPkg( equivItem.m_FootprintFPID, kk );
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) );
break;
}
}
@ -278,7 +279,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
continue;
else if( !fpid_candidate.IsEmpty() )
{
SetNewPkg( fpid_candidate, kk );
AssociateFootprint( CVPCB_ASSOCIATION( kk, fpid_candidate ) );
continue;
}
@ -290,9 +291,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
const FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( component->GetFootprintFilters()[0] );
if( module )
{
SetNewPkg( component->GetFootprintFilters()[0], kk );
}
AssociateFootprint( CVPCB_ASSOCIATION( kk, component->GetFootprintFilters()[0] ) );
}
}

View File

@ -30,6 +30,7 @@
// 'FT232BL' 'QFP:LQFP-32_7x7mm_Pitch0.8mm'
//
#include <boost/ptr_container/ptr_vector.hpp>
class FOOTPRINT_EQUIVALENCE
{

127
cvpcb/cvpcb_association.h Normal file
View File

@ -0,0 +1,127 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CVPCB_ASSOCIATION_H
#define CVPCB_ASSOCIATION_H
#include <lib_id.h>
#include <utf8.h>
/**
* A class to define a footprint association to be made in cvpcb.
*/
class CVPCB_ASSOCIATION
{
public:
/**
* Create an association event that contains all the information needed to modify the footprint
* association of a component in cvpcb.
*
* @param aComponentIndex is the index of the component to change
* @param aNewFootprint is the new footprint to give to the component
* @param aOldFootprint is the old footprint from the component
*/
CVPCB_ASSOCIATION(
unsigned int aComponentIndex, LIB_ID aNewFootprint, LIB_ID aOldFootprint = LIB_ID() ) :
m_componentIndex( aComponentIndex ),
m_newFootprint( aNewFootprint ),
m_oldFootprint( aOldFootprint )
{}
CVPCB_ASSOCIATION(
unsigned int aComponentIndex, wxString aNewFootprint, wxString aOldFootprint = "" ) :
m_componentIndex( aComponentIndex )
{
m_newFootprint.Parse( aNewFootprint, LIB_ID::ID_PCB );
m_oldFootprint.Parse( aOldFootprint, LIB_ID::ID_PCB );
}
/**
* Reverse the association.
*
* @return the reversed association
*/
CVPCB_ASSOCIATION Reverse()
{
return CVPCB_ASSOCIATION( m_componentIndex, m_oldFootprint, m_newFootprint );
}
/**
* Get the index of the component to modify the association of.
*
* @return the index of the component
*/
unsigned int GetComponentIndex() const
{
return m_componentIndex;
}
/**
* Get the new footprint to associate to the component.
*
* @return the LIB_ID of the new footprint
*/
LIB_ID GetNewFootprint() const
{
return m_newFootprint;
}
/**
* Get the old footprint of the component
*
* @return the LIB_ID of the old footprint
*/
LIB_ID GetOldFootprint() const
{
return m_oldFootprint;
}
/**
* Set the footprint that should be associated with the component
*
* @param aNewFootprint is the LIB_ID of the new footprint
*/
void SetNewFootprint( const LIB_ID& aNewFootprint )
{
m_newFootprint = aNewFootprint;
}
/**
* Set the footprint that was associated with the component before this association event
*
* @param aOldFootprint is the LIB_ID of the old footprint
*/
void SetOldFootprint( const LIB_ID& aOldFootprint )
{
m_oldFootprint = aOldFootprint;
}
private:
unsigned int m_componentIndex;
LIB_ID m_newFootprint;
LIB_ID m_oldFootprint;
};
#endif

View File

@ -44,6 +44,7 @@
#include <wx/statline.h>
#include <cvpcb.h>
#include <cvpcb_association.h>
#include <cvpcb_id.h>
#include <cvpcb_mainframe.h>
#include <display_footprints_frame.h>
@ -403,6 +404,47 @@ void CVPCB_MAINFRAME::OnQuit( wxCommandEvent& event )
}
void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation )
{
// Ensure there is data to work with
COMPONENT* component;
if( m_netlist.IsEmpty() )
return;
component = m_netlist.GetComponent( aAssociation.GetComponentIndex() );
if( component == NULL )
return;
LIB_ID fpid = aAssociation.GetNewFootprint();
// Test for validity of the requested footprint
if( !fpid.empty() && !fpid.IsValid() )
{
wxString msg =
wxString::Format( _( "\"%s\" is not a valid footprint." ), fpid.Format().wx_str() );
DisplayErrorMessage( this, msg );
}
// Set the new footprint
component->SetFPID( fpid );
// create the new component description and set it
wxString description = wxString::Format( CMP_FORMAT, aAssociation.GetComponentIndex() + 1,
GetChars( component->GetReference() ), GetChars( component->GetValue() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
m_compListBox->SetString( aAssociation.GetComponentIndex(), description );
// Mark the data as being modified
m_modified = true;
// Update the statusbar and refresh the list
DisplayStatus();
m_compListBox->Refresh();
}
void CVPCB_MAINFRAME::DeleteAll()
{
if( IsOK( this, _( "Delete all associations?" ) ) )
@ -414,10 +456,7 @@ void CVPCB_MAINFRAME::DeleteAll()
for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{
LIB_ID fpid;
m_netlist.GetComponent( i )->SetFPID( fpid );
SetNewPkg( wxEmptyString );
AssociateFootprint( CVPCB_ASSOCIATION( i, LIB_ID() ) );
}
// Remove all selections after setting the fpids
@ -853,6 +892,29 @@ COMPONENT* CVPCB_MAINFRAME::GetSelectedComponent()
}
std::vector<unsigned int> CVPCB_MAINFRAME::GetSelectedComponentIndices()
{
std::vector<unsigned int> idx;
// Check to see if anything is selected
if( m_compListBox->GetSelectedItemCount() < 1 )
return idx;
// Get the components
int lastIdx = m_compListBox->GetFirstSelected();
idx.emplace_back( lastIdx );
lastIdx = m_compListBox->GetNextSelected( lastIdx );
while( lastIdx > 0 )
{
idx.emplace_back( lastIdx );
lastIdx = m_compListBox->GetNextSelected( lastIdx );
}
return idx;
}
DISPLAY_FOOTPRINTS_FRAME* CVPCB_MAINFRAME::GetFootprintViewerFrame()
{
// returns the Footprint Viewer frame, if exists, or NULL

View File

@ -34,6 +34,7 @@
#include <wx/listctrl.h>
#include <auto_associate.h>
#include <cvpcb_association.h>
#include <listboxes.h>
#include <tool/action_menu.h>
@ -170,21 +171,11 @@ public:
void OnEnterFilteringText( wxCommandEvent& event );
/**
* Function SetNewPkg
* set the footprint name for all selected components in component list
* and selects the next component.
* @param aFootprintName = the new footprint name
*/
void SetNewPkg( const wxString& aFootprintName );
/**
* Function SetNewPkg
* Set the footprint name for the component of position aIndex in the component list
* Associate a footprint with a specific component in the list.
*
* @param aFootprintName = the new footprint name
* @param aIndex = the index of the component to modify in the component list
* @param aAssociation is the association to perform
*/
void SetNewPkg( const wxString& aFootprintName, int aIndex );
void AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation );
void BuildCmpListBox();
void BuildFOOTPRINTS_LISTBOX();
@ -286,6 +277,13 @@ public:
COMPONENT* GetSelectedComponent();
/**
* Get the indices for all the selected components in the components listbox.
*
* @return a vector containing all the indices
*/
std::vector<unsigned int> GetSelectedComponentIndices();
/**
* @return the LIB_ID of the selected footprint in footprint listview
* or a empty string if no selection

View File

@ -227,9 +227,7 @@ void FOOTPRINTS_LISTBOX::OnLeftClick( wxListEvent& event )
void FOOTPRINTS_LISTBOX::OnLeftDClick( wxListEvent& event )
{
wxString footprintName = GetSelectedFootprint();
GetParent()->SetNewPkg( footprintName );
GetParent()->GetToolManager()->RunAction( CVPCB_ACTIONS::associate, true );
}

View File

@ -42,86 +42,6 @@
#include <fp_conflict_assignment_selector.h>
void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName )
{
COMPONENT* component;
int componentIndex;
if( m_netlist.IsEmpty() )
return;
// If no component is selected, select the first one
if( m_compListBox->GetFirstSelected() < 0 )
{
componentIndex = 0;
m_compListBox->SetSelection( componentIndex, true );
}
// iterate over the selection
while( m_compListBox->GetFirstSelected() != -1 )
{
// Get the component for the current iteration
componentIndex = m_compListBox->GetFirstSelected();
component = m_netlist.GetComponent( componentIndex );
if( component == NULL )
return;
SetNewPkg( aFootprintName, componentIndex );
m_compListBox->SetSelection( componentIndex, false );
}
// select the next component, if there is one
if( componentIndex < (m_compListBox->GetCount() - 1) )
componentIndex++;
m_compListBox->SetSelection( componentIndex, true );
// update the statusbar
DisplayStatus();
}
void CVPCB_MAINFRAME::SetNewPkg( const wxString& aFootprintName, int aIndex )
{
COMPONENT* component;
if( m_netlist.IsEmpty() )
return;
component = m_netlist.GetComponent( aIndex );
if( component == NULL )
return;
LIB_ID fpid;
if( !aFootprintName.IsEmpty() )
{
wxCHECK_RET( fpid.Parse( aFootprintName, LIB_ID::ID_PCB ) < 0,
wxString::Format( _( "\"%s\" is not a valid LIB_ID." ), aFootprintName ) );
}
component->SetFPID( fpid );
// create the new component description
wxString description = wxString::Format( CMP_FORMAT, aIndex + 1,
GetChars( component->GetReference() ),
GetChars( component->GetValue() ),
GetChars( FROM_UTF8( component->GetFPID().Format().c_str() ) ) );
// Set the new description and deselect the processed component
m_compListBox->SetString( aIndex, description );
// Mark this "session" as modified
m_modified = true;
// update the statusbar
DisplayStatus();
}
/// Return true if the resultant LIB_ID has a certain nickname. The guess
/// is only made if this footprint resides in only one library.
/// @return int - 0 on success, 1 on not found, 2 on ambiguous i.e. multiple matches

View File

@ -78,6 +78,12 @@ TOOL_ACTION CVPCB_ACTIONS::gotoPreviousNA( "cvpcb.Control.GotoPreviousNA", AS_GL
// Actions to modify component associations
TOOL_ACTION CVPCB_ACTIONS::associate( "cvpcb.Control.Associate", AS_GLOBAL,
0, "",
_( "Associate footprint" ),
_( "Associate selected footprint with selected components" ),
auto_associe_xpm );
TOOL_ACTION CVPCB_ACTIONS::autoAssociate( "cvpcb.Control.AutoAssociate", AS_GLOBAL,
0, "",
_( "Automatically associate footprints" ),

View File

@ -18,10 +18,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <confirm.h>
#include <cstdint>
#include <functional>
#include <kiface_i.h>
#include <kiway_express.h>
#include <lib_id.h>
#include <tool/actions.h>
#include <cvpcb_mainframe.h>
@ -94,6 +96,38 @@ int CVPCB_CONTROL::ToggleFootprintFilter( const TOOL_EVENT& aEvent )
}
int CVPCB_CONTROL::Associate( const TOOL_EVENT& aEvent )
{
// Get the currently selected footprint
LIB_ID fpid;
wxString fp = m_frame->GetSelectedFootprint();
fpid.Parse( fp, LIB_ID::ID_PCB );
// Ignore the action if the footprint is empty (nothing selected)
if( fpid.empty() )
return 0;
// Test for validity of the requested footprint
if( !fpid.IsValid() )
{
wxString msg =
wxString::Format( _( "\"%s\" is not a valid footprint." ), fpid.Format().wx_str() );
DisplayErrorMessage( m_frame, msg );
}
// Get all the components that are selected and associate them with the current footprint
std::vector<unsigned int> sel = m_frame->GetSelectedComponentIndices();
for( auto i : sel )
{
CVPCB_ASSOCIATION newfp( i, fpid );
m_frame->AssociateFootprint( newfp );
}
return 0;
}
int CVPCB_CONTROL::AutoAssociate( const TOOL_EVENT& aEvent )
{
m_frame->AutomaticFootprintMatching();
@ -155,6 +189,7 @@ void CVPCB_CONTROL::setTransitions()
Go( &CVPCB_CONTROL::ToPreviousNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() );
// Footprint association actions
Go( &CVPCB_CONTROL::Associate, CVPCB_ACTIONS::associate.MakeEvent() );
Go( &CVPCB_CONTROL::AutoAssociate, CVPCB_ACTIONS::autoAssociate.MakeEvent() );
// Filter the footprints

View File

@ -41,6 +41,13 @@ public:
/// @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override;
/**
* Associate the selected footprint with the currently selected components.
*
* @param aEvent is the event generated by the tool framework
*/
int Associate( const TOOL_EVENT& aEvent );
/**
* Perform automatic footprint association.
*