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 The 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#include <tool/tool_manager.h>
42
43#include <ranges>
44
45
46#define ID_MATCH_FP_ALL 4200
47#define ID_MATCH_FP_SELECTED 4201
48#define ID_MATCH_FP_REF 4202
49#define ID_MATCH_FP_VAL 4203
50#define ID_MATCH_FP_ID 4204
51
52
57
58 // { update, change }
59bool g_removeExtraTextItems[2] = { false, false };
60bool g_resetTextItemLayers[2] = { false, true };
61bool g_resetTextItemEffects[2] = { false, true };
62bool g_resetTextItemContent[2] = { false, true };
63bool g_resetFabricationAttrs[2] = { false, true };
64bool g_resetClearanceOverrides[2] = { true, true };
65bool g_reset3DModels[2] = { true, true };
66
67
69 FOOTPRINT* aFootprint,
70 bool updateMode, bool selectedMode ) :
72 m_commit( aParent ),
73 m_parent( aParent ),
74 m_currentFootprint( aFootprint ),
75 m_updateMode( updateMode )
76{
77 if( !updateMode )
78 {
79 SetTitle( _( "Change Footprints" ) );
80 m_matchAll->SetLabel( _( "Change all footprints on board" ) );
81 m_matchSelected->SetLabel( _( "Change selected footprint(s)" ) );
82 m_matchSpecifiedRef->SetLabel( _( "Change footprints matching reference designator:" ) );
83 m_matchSpecifiedValue->SetLabel( _( "Change footprints matching value:" ) );
84 m_matchSpecifiedID->SetLabel( _( "Change footprints with library id:" ) );
85 m_resetTextItemLayers->SetLabel( _( "Update text layers and visibilities" ) );
86 m_resetTextItemEffects->SetLabel( _( "Update text sizes, styles and positions" ) );
87 m_resetTextItemContent->SetLabel( _( "Update text content" ) );
88 m_resetFabricationAttrs->SetLabel( _( "Update fabrication attributes" ) );
89 m_resetClearanceOverrides->SetLabel( _( "Update clearance overrides" ) );
90 m_reset3DModels->SetLabel( _( "Update 3D models" ) );
91 }
92
93#if 0 // translator hint
94 wxString x = _( "Update/reset strings: there are two cases these descriptions need to cover: "
95 "the user made overrides to a footprint on the PCB and wants to remove them, "
96 "or the user made changes to the library footprint and wants to propagate "
97 "them back to the PCB." );
98#endif
99
100 if( m_updateMode )
101 {
102 m_changeSizer->Show( false );
103 }
104 else
105 {
106 m_upperSizer->FindItem( m_matchAll )->Show( false );
107 m_newIDBrowseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
108 }
109
111 m_newID->AppendText( From_UTF8( m_currentFootprint->GetFPID().Format().c_str() ) );
112 else
113 m_upperSizer->FindItem( m_matchSelected )->Show( false );
114
115 // Use ChangeValue() instead of SetValue() so we don't generate events.
118
121
124
125 m_specifiedIDBrowseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_library ) );
126
127 m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
128 // The upper sizer has its content modified: re-layout it:
129 m_upperSizer->Layout();
130
131 // initialize match-mode
132 if( m_updateMode )
134 else
136
137 wxCommandEvent event;
138 event.SetEventObject( this );
139
140 switch( *m_matchMode )
141 {
142 case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
143 case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
144 case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
145 case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
146 case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
147 default: break;
148 }
149
156 m_reset3DModels->SetValue( g_reset3DModels[ m_updateMode ? 0 : 1 ] );
157
159 m_MessageWindow->SetFileName( Prj().GetProjectPath() + wxT( "report.txt" ) );
160
161 // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
162 // because the update and change versions of this dialog have different controls.
163 m_hash_key = TO_UTF8( GetTitle() );
164
165 wxString okLabel = m_updateMode ? _( "Update" ) : _( "Change" );
166
167 SetupStandardButtons( { { wxID_OK, okLabel },
168 { wxID_CANCEL, _( "Close" ) } } );
169
170 // Now all widgets have the size fixed, call FinishDialogSettings
172}
173
174
176{
183 g_reset3DModels[ m_updateMode ? 0 : 1 ] = m_reset3DModels->GetValue();
184}
185
186
188{
189 LIB_ID specifiedID;
190
191 switch( *m_matchMode )
192 {
193 case ID_MATCH_FP_ALL:
194 return true;
196 return aFootprint == m_currentFootprint || aFootprint->IsSelected();
197 case ID_MATCH_FP_REF:
198 return WildCompareString( m_specifiedRef->GetValue(), aFootprint->GetReference(), false );
199 case ID_MATCH_FP_VAL:
200 return WildCompareString( m_specifiedValue->GetValue(), aFootprint->GetValue(), false );
201 case ID_MATCH_FP_ID:
202 specifiedID.Parse( m_specifiedID->GetValue() );
203 return aFootprint->GetFPID() == specifiedID;
204 default:
205 return false; // just to quiet compiler warnings....
206 }
207}
208
209
211{
212 switch( *m_matchMode )
213 {
214 case ID_MATCH_FP_ALL: return m_matchAll;
219 default: return nullptr;
220 }
221}
222
223
225{
226 wxRadioButton* rb_button = getRadioButtonForMode();
227
228 wxRadioButton* rb_butt_list[] =
229 {
235 nullptr // end of list
236 };
237
238 // Ensure the button state is ok. Only one button can be checked
239 // Change button state only if its state is incorrect, otherwise
240 // we have issues depending on the platform.
241 for( int ii = 0; rb_butt_list[ii]; ++ii )
242 {
243 bool state = rb_butt_list[ii] == rb_button;
244
245 if( rb_butt_list[ii]->GetValue() != state )
246 rb_butt_list[ii]->SetValue( state );
247 }
248}
249
250
252{
254
255 if( aEvent.GetEventObject() == this )
257 else
258 m_matchAll->SetFocus();
259}
260
261
263{
265
266 if( aEvent.GetEventObject() == this )
268 else
269 m_matchSelected->SetFocus();
270}
271
272
274{
276
277 if( aEvent.GetEventObject() == this )
279 else if( aEvent.GetEventObject() != m_specifiedRef )
280 m_specifiedRef->SetFocus();
281}
282
283
285{
287
288 if( aEvent.GetEventObject() == this )
290 else if( aEvent.GetEventObject() != m_specifiedValue )
291 m_specifiedValue->SetFocus();
292}
293
294
296{
298
299 if( aEvent.GetEventObject() == this )
301 else if( aEvent.GetEventObject() != m_specifiedID )
302 m_specifiedID->SetFocus();
303}
304
305
307{
308 m_removeExtraBox->SetValue( aCheck );
309 m_resetTextItemLayers->SetValue( aCheck );
310 m_resetTextItemEffects->SetValue( aCheck );
311 m_resetTextItemContent->SetValue( aCheck );
312 m_resetFabricationAttrs->SetValue( aCheck );
313 m_resetClearanceOverrides->SetValue( aCheck );
314 m_reset3DModels->SetValue( aCheck );
315}
316
317
318void DIALOG_EXCHANGE_FOOTPRINTS::OnOKClicked( wxCommandEvent& aEvent )
319{
321 wxBusyCursor dummy;
322
324 m_MessageWindow->Flush( false );
325
326 m_newFootprints.clear();
328 m_commit.Push( m_updateMode ? _( "Update Footprint" ) : _( "Change Footprint" ) );
329 selTool->AddItemsToSel( &m_newFootprints );
330
331 m_MessageWindow->Flush( false );
332
333 WINDOW_THAWER thawer( m_parent );
335}
336
337
339{
340 LIB_ID newFPID;
341
342 if( m_parent->GetBoard()->Footprints().empty() )
343 return;
344
345 if( !m_updateMode )
346 {
347 newFPID.Parse( m_newID->GetValue() );
348
349 if( !newFPID.IsValid() )
350 return;
351 }
352
353 /*
354 * NB: the change is done from the last footprint because processFootprint() modifies the
355 * last item in the list.
356 */
357 for( FOOTPRINT* footprint : std::ranges::reverse_view( m_parent->GetBoard()->Footprints() ) )
358 {
359 if( !isMatch( footprint ) )
360 continue;
361
362 if( m_updateMode )
363 processFootprint( footprint, footprint->GetFPID() );
364 else
365 processFootprint( footprint, newFPID );
366 }
367}
368
369
371{
372 LIB_ID oldFPID = aFootprint->GetFPID();
373 wxString msg;
374
375 // Load new footprint.
376 if( m_updateMode )
377 {
378 msg.Printf( _( "Updated footprint %s (%s)" ) + wxS( ": " ),
379 aFootprint->GetReference(),
380 oldFPID.Format().c_str() );
381 }
382 else
383 {
384 msg.Printf( _( "Changed footprint %s from '%s' to '%s'" ) + wxS( ": " ),
385 aFootprint->GetReference(),
386 oldFPID.Format().c_str(),
387 aNewFPID.Format().c_str() );
388 }
389
390 FOOTPRINT* newFootprint = m_parent->LoadFootprint( aNewFPID );
391
392 if( !newFootprint )
393 {
394 msg += _( "*** library footprint not found ***" );
396 return;
397 }
398
399 bool updated = !m_updateMode || aFootprint->FootprintNeedsUpdate( newFootprint );
400
401 m_parent->ExchangeFootprint( aFootprint, newFootprint, m_commit,
402 m_removeExtraBox->GetValue(),
403 m_resetTextItemLayers->GetValue(),
404 m_resetTextItemEffects->GetValue(),
405 m_resetTextItemContent->GetValue(),
406 m_resetFabricationAttrs->GetValue(),
407 m_resetClearanceOverrides->GetValue(),
408 m_reset3DModels->GetValue(),
409 &updated );
410
411 if( aFootprint == m_currentFootprint )
412 m_currentFootprint = newFootprint;
413
414 if( newFootprint )
415 m_newFootprints.push_back( newFootprint );
416
417 if( m_updateMode && !updated )
418 {
419 msg += _( ": (no changes)" );
421 }
422 else
423 {
424 msg += _( ": OK" );
426 }
427}
428
429
431{
432 wxString newname = m_newID->GetValue();
433
434 if( KIWAY_PLAYER* frame = Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, this ) )
435 {
437 {
438 /*
439 * Symbol netlist format:
440 * pinNumber pinName <tab> pinNumber pinName...
441 * fpFilter fpFilter...
442 */
443 wxString netlist;
444
445 wxArrayString pins;
446
447 for( const wxString& pad : m_currentFootprint->GetUniquePadNumbers() )
448 pins.push_back( pad + ' ' + wxEmptyString /* leave pinName empty */ );
449
450 if( !pins.IsEmpty() )
451 netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
452
453 netlist << wxS( "\r" );
454
456
457 std::string payload( netlist.ToStdString() );
459 frame->KiwayMailIn( mail );
460 }
461
462 if( frame->ShowModal( &newname, this ) )
463 {
464 if( event.GetEventObject() == m_newIDBrowseButton )
465 m_newID->SetValue( newname );
466 else
467 m_specifiedID->SetValue( newname );
468 }
469
470 frame->Destroy();
471 }
472}
473
474
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition: bitmap.cpp:110
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
const FOOTPRINTS & Footprints() const
Definition: board.h:358
Class DIALOG_EXCHANGE_FOOTPRINTS_BASE.
void OnMatchIDClicked(wxCommandEvent &aEvent) override
void updateMatchModeRadioButtons(wxUpdateUIEvent &aEvent) override
void processFootprint(FOOTPRINT *aFootprint, const LIB_ID &aNewFPID)
void OnMatchValueClicked(wxCommandEvent &aEvent) override
void OnOKClicked(wxCommandEvent &aEvent) override
void OnMatchSelectedClicked(wxCommandEvent &aEvent) override
void OnMatchRefClicked(wxCommandEvent &aEvent) override
void ViewAndSelectFootprint(wxCommandEvent &aEvent) override
DIALOG_EXCHANGE_FOOTPRINTS(PCB_EDIT_FRAME *aParent, FOOTPRINT *aFootprint, bool updateMode, bool selectedMode)
void OnMatchAllClicked(wxCommandEvent &aEvent) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:66
void SetupStandardButtons(std::map< int, wxString > aLabels={})
std::string m_hash_key
Definition: dialog_shim.h:194
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:126
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:2032
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:251
wxString GetFilters() const
Definition: footprint.h:275
const wxString & GetValue() const
Definition: footprint.h:647
const wxString & GetReference() const
Definition: footprint.h:625
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:52
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
UTF8 Format() const
Definition: lib_id.cpp:119
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
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 resetTextContent=true, bool resetClearanceOverrides=true, bool reset3DModels=true, bool *aUpdated=nullptr)
Replace aExisting footprint by aNew footprint using the Existing footprint settings (position,...
The selection tool: currently supports:
int AddItemsToSel(const TOOL_EVENT &aEvent)
void SetBitmap(const wxBitmapBundle &aBmp)
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
const char * c_str() const
Definition: utf8.h:103
void Clear()
Clears the report panel.
void SetLazyUpdate(bool aLazyUpdate)
Set the lazy update.
void SetFileName(const wxString &aReportFileName)
Set the report full file name to the string.
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Report the string.
void Flush(bool aSort=false)
Force updating the HTML page, after the report is built in lazy mode If aSort = true,...
#define ID_MATCH_FP_ALL
bool g_resetTextItemLayers[2]
#define ID_MATCH_FP_VAL
bool g_resetClearanceOverrides[2]
bool g_resetFabricationAttrs[2]
bool g_resetTextItemEffects[2]
bool g_resetTextItemContent[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:429
@ CTX_LINE
Definition: string_utils.h:59