2019-08-09 22:13:17 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 Ian McInerney <Ian.S.McInerney@ieee.org>
|
2020-08-18 14:17:16 +00:00
|
|
|
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
2019-08-09 22:13:17 +00:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <confirm.h>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <functional>
|
2021-09-14 22:45:14 +00:00
|
|
|
#include <kiface_base.h>
|
2019-08-09 22:13:17 +00:00
|
|
|
#include <kiway_express.h>
|
|
|
|
#include <lib_id.h>
|
|
|
|
#include <tool/actions.h>
|
|
|
|
#include <tool/tool_manager.h>
|
|
|
|
#include <wx/clipbrd.h>
|
2021-06-03 12:11:15 +00:00
|
|
|
#include <wx/log.h>
|
2019-08-09 22:13:17 +00:00
|
|
|
|
|
|
|
#include <cvpcb_association.h>
|
|
|
|
#include <cvpcb_mainframe.h>
|
|
|
|
#include <dialogs/dialog_config_equfiles.h>
|
|
|
|
#include <display_footprints_frame.h>
|
|
|
|
#include <listboxes.h>
|
|
|
|
#include <tools/cvpcb_actions.h>
|
|
|
|
#include <tools/cvpcb_association_tool.h>
|
|
|
|
|
|
|
|
using namespace std::placeholders;
|
|
|
|
|
|
|
|
|
|
|
|
CVPCB_ASSOCIATION_TOOL::CVPCB_ASSOCIATION_TOOL() :
|
|
|
|
TOOL_INTERACTIVE( "cvpcb.Association" ),
|
|
|
|
m_frame( nullptr )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::CopyAssoc( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2021-02-05 18:18:30 +00:00
|
|
|
LIB_ID fpid;
|
2019-10-06 10:19:41 +00:00
|
|
|
|
2021-02-05 18:18:30 +00:00
|
|
|
if( m_frame->GetFocusedControl() == CVPCB_MAINFRAME::CONTROL_FOOTPRINT )
|
2020-12-17 23:32:23 +00:00
|
|
|
fpid.Parse( m_frame->GetSelectedFootprint() );
|
2021-02-05 18:18:30 +00:00
|
|
|
else if( m_frame->GetSelectedComponent() )
|
|
|
|
fpid = m_frame->GetSelectedComponent()->GetFPID();
|
|
|
|
else
|
|
|
|
return 0;
|
2019-08-09 22:13:17 +00:00
|
|
|
|
|
|
|
// if no valid fpid, then skip
|
|
|
|
if( !fpid.IsValid() )
|
|
|
|
return 0;
|
|
|
|
|
2021-02-05 18:18:30 +00:00
|
|
|
wxLogNull raiiDoNotLog; // disable logging of failed clipboard actions
|
2021-01-29 19:13:12 +00:00
|
|
|
|
2019-08-09 22:13:17 +00:00
|
|
|
if( wxTheClipboard->Open() )
|
|
|
|
{
|
2020-08-18 14:17:16 +00:00
|
|
|
wxTheClipboard->SetData( new wxTextDataObject( fpid.GetUniStringLibId() ) );
|
2019-08-09 22:13:17 +00:00
|
|
|
wxTheClipboard->Flush();
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::CutAssoc( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2019-10-06 10:19:41 +00:00
|
|
|
// If using the keyboard, only cut in the component frame
|
2021-02-05 18:18:30 +00:00
|
|
|
if( m_frame->GetFocusedControl()
|
|
|
|
&& m_frame->GetFocusedControl() != CVPCB_MAINFRAME::CONTROL_COMPONENT )
|
|
|
|
{
|
2019-08-09 22:13:17 +00:00
|
|
|
return 0;
|
2021-02-05 18:18:30 +00:00
|
|
|
}
|
2019-08-09 22:13:17 +00:00
|
|
|
|
|
|
|
// Get the selection, but only use the first one
|
|
|
|
COMPONENT* comp = m_frame->GetSelectedComponent();
|
|
|
|
std::vector<unsigned int> idx = m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS );
|
|
|
|
|
|
|
|
if( idx.empty() || !comp )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Get the fpid
|
|
|
|
LIB_ID fpid;
|
|
|
|
fpid = comp->GetFPID();
|
|
|
|
|
|
|
|
// if no valid fpid, then skip
|
|
|
|
if( !fpid.IsValid() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Save it to the clipboard
|
|
|
|
{
|
2021-01-29 19:13:12 +00:00
|
|
|
wxLogNull doNotLog; // disable logging of failed clipboard actions
|
|
|
|
|
|
|
|
if( wxTheClipboard->Open() )
|
2019-08-09 22:13:17 +00:00
|
|
|
{
|
2021-01-29 19:13:12 +00:00
|
|
|
if( !wxTheClipboard->SetData( new wxTextDataObject( fpid.GetUniStringLibId() ) ) )
|
|
|
|
{
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxTheClipboard->Flush();
|
2019-08-09 22:13:17 +00:00
|
|
|
wxTheClipboard->Close();
|
2021-01-29 19:13:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-08-09 22:13:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-10-06 10:19:41 +00:00
|
|
|
}
|
2019-08-09 22:13:17 +00:00
|
|
|
|
|
|
|
// Remove the association
|
|
|
|
m_frame->AssociateFootprint( CVPCB_ASSOCIATION( idx.front(), "" ) );
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::PasteAssoc( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
// Get the selection
|
|
|
|
std::vector<unsigned int> idx = m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS );
|
|
|
|
|
|
|
|
if( idx.empty() )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Get the clipboard data and ensure it is valid
|
|
|
|
LIB_ID fpid;
|
|
|
|
wxTextDataObject data;
|
|
|
|
|
2019-10-06 10:19:41 +00:00
|
|
|
{
|
2021-01-29 19:13:12 +00:00
|
|
|
wxLogNull doNotLog; // disable logging of failed clipboard actions
|
|
|
|
|
|
|
|
if( wxTheClipboard->Open() )
|
|
|
|
{
|
|
|
|
wxTheClipboard->GetData( data );
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2019-10-06 10:19:41 +00:00
|
|
|
}
|
2019-08-09 22:13:17 +00:00
|
|
|
|
2020-12-17 23:32:23 +00:00
|
|
|
if( fpid.Parse( data.GetText() ) >= 0 )
|
2019-08-09 22:13:17 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Assign the fpid to the selections
|
|
|
|
bool firstAssoc = true;
|
2022-07-29 21:02:35 +00:00
|
|
|
|
|
|
|
for( unsigned int i : idx )
|
2019-08-09 22:13:17 +00:00
|
|
|
{
|
|
|
|
m_frame->AssociateFootprint( CVPCB_ASSOCIATION( i, fpid ), firstAssoc );
|
|
|
|
firstAssoc = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-18 14:17:16 +00:00
|
|
|
|
2019-08-09 22:13:17 +00:00
|
|
|
void CVPCB_ASSOCIATION_TOOL::Reset( RESET_REASON aReason )
|
|
|
|
{
|
|
|
|
m_frame = getEditFrame<CVPCB_MAINFRAME>();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::Undo( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->UndoAssociation();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::Redo( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->RedoAssociation();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::Associate( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
// Get the currently selected footprint
|
|
|
|
LIB_ID fpid;
|
|
|
|
wxString fp = m_frame->GetSelectedFootprint();
|
2020-12-17 23:32:23 +00:00
|
|
|
fpid.Parse( fp );
|
2019-08-09 22:13:17 +00:00
|
|
|
|
|
|
|
// 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() )
|
|
|
|
{
|
2021-06-28 23:44:07 +00:00
|
|
|
wxString msg = wxString::Format( _( "'%s' is not a valid footprint." ),
|
|
|
|
fpid.Format().wx_str() );
|
2019-08-09 22:13:17 +00:00
|
|
|
DisplayErrorMessage( m_frame, msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get all the components that are selected and associate them with the current footprint
|
|
|
|
bool firstAssoc = true;
|
2022-07-29 21:02:35 +00:00
|
|
|
|
|
|
|
for( unsigned int i : m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS ) )
|
2019-08-09 22:13:17 +00:00
|
|
|
{
|
|
|
|
CVPCB_ASSOCIATION newfp( i, fpid );
|
|
|
|
m_frame->AssociateFootprint( newfp, firstAssoc );
|
|
|
|
firstAssoc = false;
|
|
|
|
}
|
|
|
|
|
2019-08-11 08:47:51 +00:00
|
|
|
// Move to the next not associated component
|
2023-06-26 22:16:51 +00:00
|
|
|
m_toolMgr->PostAction( CVPCB_ACTIONS::gotoNextNA );
|
2019-08-11 08:47:51 +00:00
|
|
|
|
2019-08-09 22:13:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::AutoAssociate( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
m_frame->AutomaticFootprintMatching();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::DeleteAssoc( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
2022-07-29 21:02:35 +00:00
|
|
|
// Delete all the selected components' associations
|
2019-08-09 22:13:17 +00:00
|
|
|
bool firstAssoc = true;
|
2022-07-29 21:02:35 +00:00
|
|
|
|
|
|
|
for( unsigned int i : m_frame->GetComponentIndices( CVPCB_MAINFRAME::SEL_COMPONENTS ) )
|
2019-08-09 22:13:17 +00:00
|
|
|
{
|
|
|
|
m_frame->AssociateFootprint( CVPCB_ASSOCIATION( i, LIB_ID() ), firstAssoc );
|
|
|
|
firstAssoc = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CVPCB_ASSOCIATION_TOOL::DeleteAll( const TOOL_EVENT& aEvent )
|
|
|
|
{
|
|
|
|
if( IsOK( m_frame, _( "Delete all associations?" ) ) )
|
|
|
|
{
|
|
|
|
// Remove all selections to avoid issues when setting the fpids
|
|
|
|
m_frame->SetSelectedComponent( -1, true );
|
|
|
|
|
|
|
|
bool firstAssoc = true;
|
2022-07-29 21:02:35 +00:00
|
|
|
|
|
|
|
for( unsigned int i : m_frame->GetComponentIndices( CVPCB_MAINFRAME::ALL_COMPONENTS ) )
|
2019-08-09 22:13:17 +00:00
|
|
|
{
|
|
|
|
m_frame->AssociateFootprint( CVPCB_ASSOCIATION( i, LIB_ID() ), firstAssoc );
|
|
|
|
firstAssoc = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove all selections after setting the fpids and select the first component
|
|
|
|
m_frame->SetSelectedComponent( -1, true );
|
|
|
|
m_frame->SetSelectedComponent( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the status display
|
|
|
|
m_frame->DisplayStatus();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CVPCB_ASSOCIATION_TOOL::setTransitions()
|
|
|
|
{
|
|
|
|
// Association
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::Associate, CVPCB_ACTIONS::associate.MakeEvent() );
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::AutoAssociate, CVPCB_ACTIONS::autoAssociate.MakeEvent() );
|
|
|
|
|
|
|
|
// Deletion
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::DeleteAll, CVPCB_ACTIONS::deleteAll.MakeEvent() );
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::DeleteAssoc, CVPCB_ACTIONS::deleteAssoc.MakeEvent() );
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::Undo, ACTIONS::undo.MakeEvent() );
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::Redo, ACTIONS::redo.MakeEvent() );
|
|
|
|
|
|
|
|
// Clipboard
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::CutAssoc, ACTIONS::cut.MakeEvent() );
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::CopyAssoc, ACTIONS::copy.MakeEvent() );
|
|
|
|
Go( &CVPCB_ASSOCIATION_TOOL::PasteAssoc, ACTIONS::paste.MakeEvent() );
|
|
|
|
}
|