KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_exchange_footprints.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
7 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <bitmaps.h>
28#include <board.h>
29#include <footprint.h>
30#include <pad.h>
32#include <string_utils.h>
33#include <kiway.h>
34#include <kiway_express.h>
35#include <macros.h>
36#include <pcb_edit_frame.h>
37#include <pcbnew_settings.h>
40
41
42#define ID_MATCH_FP_ALL 4200
43#define ID_MATCH_FP_SELECTED 4201
44#define ID_MATCH_FP_REF 4202
45#define ID_MATCH_FP_VAL 4203
46#define ID_MATCH_FP_ID 4204
47
48
53
54 // { update, change }
55bool g_removeExtraTextItems[2] = { false, false };
56bool g_resetTextItemLayers[2] = { false, true };
57bool g_resetTextItemEffects[2] = { false, true };
58bool g_resetFabricationAttrs[2] = { false, true };
59bool g_reset3DModels[2] = { true, true };
60
61
63 FOOTPRINT* aFootprint,
64 bool updateMode, bool selectedMode ) :
66 m_commit( aParent ),
67 m_parent( aParent ),
68 m_currentFootprint( aFootprint ),
69 m_updateMode( updateMode )
70{
71 if( !updateMode )
72 {
73 SetTitle( _( "Change Footprints" ) );
74 m_matchAll->SetLabel( _( "Change all footprints on board" ) );
75 m_matchSelected->SetLabel( _( "Change selected footprint(s)" ) );
76 m_matchSpecifiedRef->SetLabel( _( "Change footprints matching reference designator:" ) );
77 m_matchSpecifiedValue->SetLabel( _( "Change footprints matching value:" ) );
78 m_matchSpecifiedID->SetLabel( _( "Change footprints with library id:" ) );
79 m_resetTextItemLayers->SetLabel( _( "Update text layers and visibilities" ) );
80 m_resetTextItemEffects->SetLabel( _( "Update text sizes, styles and positions" ) );
81 m_resetFabricationAttrs->SetLabel( _( "Update fabrication attributes" ) );
82 m_reset3DModels->SetLabel( _( "Update 3D models" ) );
83 }
84
85#if 0 // translator hint
86 wxString x = _( "Update/reset strings: there are two cases these descriptions need to cover: "
87 "the user made overrides to a footprint on the PCB and wants to remove them, "
88 "or the user made changes to the library footprint and wants to propagate "
89 "them back to the PCB." );
90#endif
91
92 if( m_updateMode )
93 {
94 m_changeSizer->Show( false );
95 }
96 else
97 {
98 m_upperSizer->FindItem( m_matchAll )->Show( false );
99 m_newIDBrowseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
100 }
101
103 m_newID->AppendText( From_UTF8( m_currentFootprint->GetFPID().Format().c_str() ) );
104 else
105 m_upperSizer->FindItem( m_matchSelected )->Show( false );
106
107 // Use ChangeValue() instead of SetValue() so we don't generate events.
110
113
116
117 m_specifiedIDBrowseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
118
119 m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
120 // The upper sizer has its content modified: re-layout it:
121 m_upperSizer->Layout();
122
123 // initialize match-mode
124 if( m_updateMode )
126 else
128
129 wxCommandEvent event;
130 event.SetEventObject( this );
131
132 switch( *m_matchMode )
133 {
134 case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
135 case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
136 case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
137 case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
138 case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
139 default: break;
140 }
141
146 m_reset3DModels->SetValue( g_reset3DModels[ m_updateMode ? 0 : 1 ] );
147
149 m_MessageWindow->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
150
151 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
152 // because the update and change versions of this dialog have different controls.
153 m_hash_key = TO_UTF8( GetTitle() );
154
155 wxString okLabel = m_updateMode ? _( "Update" ) : _( "Change" );
156
157 SetupStandardButtons( { { wxID_OK, okLabel },
158 { wxID_CANCEL, _( "Close" ) } } );
159
160 // Now all widgets have the size fixed, call FinishDialogSettings
162}
163
164
166{
171 g_reset3DModels[ m_updateMode ? 0 : 1 ] = m_reset3DModels->GetValue();
172}
173
174
176{
177 LIB_ID specifiedID;
178
179 switch( *m_matchMode )
180 {
181 case ID_MATCH_FP_ALL:
182 return true;
184 return aFootprint == m_currentFootprint || aFootprint->IsSelected();
185 case ID_MATCH_FP_REF:
186 return WildCompareString( m_specifiedRef->GetValue(), aFootprint->GetReference(), false );
187 case ID_MATCH_FP_VAL:
188 return WildCompareString( m_specifiedValue->GetValue(), aFootprint->GetValue(), false );
189 case ID_MATCH_FP_ID:
190 specifiedID.Parse( m_specifiedID->GetValue() );
191 return aFootprint->GetFPID() == specifiedID;
192 default:
193 return false; // just to quiet compiler warnings....
194 }
195}
196
197
199{
200 switch( *m_matchMode )
201 {
202 case ID_MATCH_FP_ALL: return m_matchAll;
207 default: return nullptr;
208 }
209}
210
211
213{
214 wxRadioButton* rb_button = getRadioButtonForMode();
215
216 wxRadioButton* rb_butt_list[] =
217 {
223 nullptr // end of list
224 };
225
226 // Ensure the button state is ok. Only one button can be checked
227 // Change button state only if its state is incorrect, otherwise
228 // we have issues depending on the platform.
229 for( int ii = 0; rb_butt_list[ii]; ++ii )
230 {
231 bool state = rb_butt_list[ii] == rb_button;
232
233 if( rb_butt_list[ii]->GetValue() != state )
234 rb_butt_list[ii]->SetValue( state );
235 }
236}
237
238
240{
242
243 if( event.GetEventObject() == this )
245 else
246 m_matchAll->SetFocus();
247}
248
249
251{
253
254 if( event.GetEventObject() == this )
256 else
257 m_matchSelected->SetFocus();
258}
259
260
262{
264
265 if( event.GetEventObject() == this )
267 else if( event.GetEventObject() != m_specifiedRef )
268 m_specifiedRef->SetFocus();
269}
270
271
273{
275
276 if( event.GetEventObject() == this )
278 else if( event.GetEventObject() != m_specifiedValue )
279 m_specifiedValue->SetFocus();
280}
281
282
284{
286
287 if( event.GetEventObject() == this )
289 else if( event.GetEventObject() != m_specifiedID )
290 m_specifiedID->SetFocus();
291}
292
293
294void DIALOG_EXCHANGE_FOOTPRINTS::OnOKClicked( wxCommandEvent& event )
295{
296 wxBusyCursor dummy;
297
299 m_MessageWindow->Flush( false );
300
302
303 m_parent->Compile_Ratsnest( true );
305
306 m_MessageWindow->Flush( false );
307
308 m_commit.Push( wxT( "Changed footprint" ) );
309}
310
311
313{
314 LIB_ID newFPID;
315
316 if( m_parent->GetBoard()->Footprints().empty() )
317 return;
318
319 if( !m_updateMode )
320 {
321 newFPID.Parse( m_newID->GetValue() );
322
323 if( !newFPID.IsValid() )
324 return;
325 }
326
327 /*
328 * NB: the change is done from the last footprint because processFootprint() modifies the
329 * last item in the list.
330 */
331 for( auto it = m_parent->GetBoard()->Footprints().rbegin();
332 it != m_parent->GetBoard()->Footprints().rend(); it++ )
333 {
334 FOOTPRINT* footprint = *it;
335
336 if( !isMatch( footprint ) )
337 continue;
338
339 if( m_updateMode )
340 processFootprint( footprint, footprint->GetFPID() );
341 else
342 processFootprint( footprint, newFPID );
343 }
344}
345
346
348{
349 LIB_ID oldFPID = aFootprint->GetFPID();
350 wxString msg;
351
352 // Load new footprint.
353 if( m_updateMode )
354 {
355 msg.Printf( _( "Updated footprint %s (%s)" ) + wxS( ": " ),
356 aFootprint->GetReference(),
357 oldFPID.Format().c_str() );
358 }
359 else
360 {
361 msg.Printf( _( "Changed footprint %s from '%s' to '%s'" ) + wxS( ": " ),
362 aFootprint->GetReference(),
363 oldFPID.Format().c_str(),
364 aNewFPID.Format().c_str() );
365 }
366
367 FOOTPRINT* newFootprint = m_parent->LoadFootprint( aNewFPID );
368
369 if( !newFootprint )
370 {
371 msg += _( "*** library footprint not found ***" );
373 return;
374 }
375
376 bool updated = !m_updateMode || aFootprint->FootprintNeedsUpdate( newFootprint );
377
378 m_parent->ExchangeFootprint( aFootprint, newFootprint, m_commit,
379 m_removeExtraBox->GetValue(),
380 m_resetTextItemLayers->GetValue(),
381 m_resetTextItemEffects->GetValue(),
382 m_resetFabricationAttrs->GetValue(),
383 m_reset3DModels->GetValue(),
384 &updated );
385
386 // Update footprint field with the new FPID
387 newFootprint->Footprint().SetText( aNewFPID.Format() );
388
389 if( aFootprint == m_currentFootprint )
390 m_currentFootprint = newFootprint;
391
392 if( m_updateMode && !updated )
393 {
394 msg += _( ": (no changes)" );
396 }
397 else
398 {
399 msg += _( ": OK" );
401 }
402}
403
404
406{
407 wxString newname = m_newID->GetValue();
408
409 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, this ) )
410 {
412 {
413 /*
414 * Symbol netlist format:
415 * pinNumber pinName <tab> pinNumber pinName...
416 * fpFilter fpFilter...
417 */
418 wxString netlist;
419
420 wxArrayString pins;
421
422 for( const wxString& pad : m_currentFootprint->GetUniquePadNumbers() )
423 pins.push_back( pad + ' ' + wxEmptyString /* leave pinName empty */ );
424
425 if( !pins.IsEmpty() )
426 netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
427
428 netlist << wxS( "\r" );
429
431
432 std::string payload( netlist.ToStdString() );
434 frame->KiwayMailIn( mail );
435 }
436
437 if( frame->ShowModal( &newname, this ) )
438 {
439 if( event.GetEventObject() == m_newIDBrowseButton )
440 m_newID->SetValue( newname );
441 else
442 m_specifiedID->SetValue( newname );
443 }
444
445 frame->Destroy();
446 }
447}
448
449
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
const FOOTPRINTS & Footprints() const
Definition: board.h:323
Class DIALOG_EXCHANGE_FOOTPRINTS_BASE.
void updateMatchModeRadioButtons(wxUpdateUIEvent &event) override
void OnMatchValueClicked(wxCommandEvent &event) override
void processFootprint(FOOTPRINT *aFootprint, const LIB_ID &aNewFPID)
void ViewAndSelectFootprint(wxCommandEvent &event) override
DIALOG_EXCHANGE_FOOTPRINTS(PCB_EDIT_FRAME *aParent, FOOTPRINT *aFootprint, bool updateMode, bool selectedMode)
void OnMatchIDClicked(wxCommandEvent &event) override
void OnMatchSelectedClicked(wxCommandEvent &event) override
void OnMatchAllClicked(wxCommandEvent &event) override
void OnMatchRefClicked(wxCommandEvent &event) override
void OnOKClicked(wxCommandEvent &event) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:102
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:210
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
bool IsSelected() const
Definition: eda_item.h:109
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:181
std::set< wxString > GetUniquePadNumbers(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the names of the unique, non-blank pads.
Definition: footprint.cpp:1852
PCB_FIELD & Footprint()
Definition: footprint.h:626
bool FootprintNeedsUpdate(const FOOTPRINT *aLibFP, int aCompareFlags=0, REPORTER *aReporter=nullptr)
Return true if a board footprint differs from the library version.
const LIB_ID & GetFPID() const
Definition: footprint.h:233
wxString GetFilters() const
Definition: footprint.h:258
const wxString & GetValue() const
Definition: footprint.h:610
const wxString & GetReference() const
Definition: footprint.h:588
Carry a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition: kiway_express.h:40
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:65
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:51
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
UTF8 Format() const
Definition: lib_id.cpp:118
FOOTPRINT * LoadFootprint(const LIB_ID &aFootprintId)
Attempt to load aFootprintId from the footprint library table.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
void Compile_Ratsnest(bool aDisplayStatus)
Create the entire board ratsnest.
Definition: ratsnest.cpp:35
The main frame for Pcbnew.
void ExchangeFootprint(FOOTPRINT *aExisting, FOOTPRINT *aNew, BOARD_COMMIT &aCommit, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true, bool resetFabricationAttrs=true, bool reset3DModels=true, bool *aUpdated=nullptr)
Replace aExisting footprint by aNew footprint using the Existing footprint settings (position,...
void SetBitmap(const wxBitmapBundle &aBmp)
const char * c_str() const
Definition: utf8.h:103
void Clear()
return the number of messages matching the given severity mask.
void SetLazyUpdate(bool aLazyUpdate)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true,...
void SetFileName(const wxString &aReportFileName)
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Reports the string.
void Flush(bool aSort=false)
Set the visible severity filter.
#define ID_MATCH_FP_ALL
bool g_resetTextItemLayers[2]
#define ID_MATCH_FP_VAL
bool g_resetFabricationAttrs[2]
bool g_resetTextItemEffects[2]
#define ID_MATCH_FP_SELECTED
#define ID_MATCH_FP_REF
int g_matchModeForExchange
int g_matchModeForUpdateSelected
int g_matchModeForUpdate
bool g_reset3DModels[2]
bool g_removeExtraTextItems[2]
#define ID_MATCH_FP_ID
int g_matchModeForExchangeSelected
#define _(s)
@ FRAME_FOOTPRINT_CHOOSER
Definition: frame_type.h:44
This file contains miscellaneous commonly used macros and functions.
@ MAIL_SYMBOL_NETLIST
Definition: mail_type.h:45
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
std::vector< FAB_LAYER_COLOR > dummy
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
wxString From_UTF8(const char *cstring)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:391
@ CTX_LINE
Definition: string_utils.h:59