KiCad PCB EDA Suite
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 <dick@softplc.com>
6  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2018 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_commit.h>
29 #include <class_board.h>
30 #include <class_module.h>
32 #include <fctsys.h>
33 #include <kicad_string.h>
34 #include <kiway.h>
35 #include <macros.h>
36 #include <pcb_edit_frame.h>
37 #include <pcbnew_settings.h>
38 #include <project.h>
39 #include <wx_html_report_panel.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 
55 bool g_resetTextItemLayers = false;
57 bool g_reset3DModels = false;
58 
59 
61  bool updateMode, bool selectedMode ) :
63  m_commit( aParent ),
64  m_parent( aParent ),
65  m_currentModule( aModule ),
66  m_updateMode( updateMode )
67 {
68  wxString title = updateMode ? _( "Update Footprints from Library" ) : _( "Change Footprints" );
69  wxString verb = updateMode ? _( "Update" ) : _( "Change" );
70  wxString label;
71 
72  SetTitle( title );
73 
74  if( m_updateMode )
75  {
76  label.Printf( m_matchAll->GetLabel(), verb );
77  m_matchAll->SetLabel( label );
78  m_changeSizer->Show( false );
79  }
80  else
81  {
82  m_upperSizer->FindItem( m_matchAll )->Show( false );
84  }
85 
86  if( m_currentModule )
87  {
88  label.Printf( m_matchSelected->GetLabel(), verb );
89  m_matchSelected->SetLabel( label );
90  m_newID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
91  }
92  else
93  m_upperSizer->FindItem( m_matchSelected )->Show( false );
94 
95  label.Printf( m_matchSpecifiedRef->GetLabel(), verb );
96  m_matchSpecifiedRef->SetLabel( label );
97 
98  // Use ChangeValue() instead of SetValue() so we don't generate events.
99  if( m_currentModule )
100  m_specifiedRef->ChangeValue( m_currentModule->GetReference() );
101 
102  label.Printf( m_matchSpecifiedValue->GetLabel(), verb );
103  m_matchSpecifiedValue->SetLabel( label );
104 
105  if( m_currentModule )
106  m_specifiedValue->ChangeValue( m_currentModule->GetValue() );
107 
108  label.Printf( m_matchSpecifiedID->GetLabel(), verb );
109  m_matchSpecifiedID->SetLabel( label );
110 
111  if( m_currentModule )
112  m_specifiedID->ChangeValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
113 
115 
116  m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
117  // The upper sizer has its content modified: re-layout it:
118  m_upperSizer->Layout();
119 
120  // initialize match-mode
121  if( m_updateMode )
123  else
125 
126  wxCommandEvent event;
127  event.SetEventObject( this );
128 
129  switch( *m_matchMode )
130  {
131  case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
132  case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
133  case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
134  case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
135  case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
136  default: break;
137  }
138 
142  m_reset3DModels->SetValue( g_reset3DModels );
143 
145 
146  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
147  // because the update and change versions of this dialog have different controls.
148  m_hash_key = TO_UTF8( GetTitle() );
149 
150  // Ensure m_closeButton (with id = wxID_CANCEL) has the right label
151  // (to fix automatic renaming of button label )
152  m_sdbSizerCancel->SetLabel( _( "Close" ) );
153 
154  m_sdbSizerApply->SetDefault();
155 
156  // Now all widgets have the size fixed, call FinishDialogSettings
158 }
159 
160 
162 {
166  g_reset3DModels = m_reset3DModels->GetValue();
167 }
168 
169 
171 {
172  LIB_ID specifiedID;
173 
174  switch( *m_matchMode )
175  {
176  case ID_MATCH_FP_ALL:
177  return true;
179  return aModule == m_currentModule;
180  case ID_MATCH_FP_REF:
181  return WildCompareString( m_specifiedRef->GetValue(), aModule->GetReference(), false );
182  case ID_MATCH_FP_VAL:
183  return WildCompareString( m_specifiedValue->GetValue(), aModule->GetValue(), false );
184  case ID_MATCH_FP_ID:
185  specifiedID.Parse( m_specifiedID->GetValue(), LIB_ID::ID_PCB );
186  return aModule->GetFPID() == specifiedID;
187  default:
188  return false; // just to quiet compiler warnings....
189  }
190 }
191 
192 
194 {
195  switch( *m_matchMode )
196  {
197  case ID_MATCH_FP_ALL: return m_matchAll;
201  case ID_MATCH_FP_ID: return m_matchSpecifiedID;
202  default: return nullptr;
203  }
204 }
205 
206 
208 {
209  wxRadioButton* rb_button = getRadioButtonForMode();
210 
211  wxRadioButton* rb_butt_list[] =
212  {
213  m_matchAll,
218  nullptr // end of list
219  };
220 
221  // Ensure the button state is ok. Only one button can be checked
222  // Change button state only if its state is incorrect, otherwise
223  // we have issues depending on the platform.
224  for( int ii = 0; rb_butt_list[ii]; ++ii )
225  {
226  bool state = rb_butt_list[ii] == rb_button;
227 
228  if( rb_butt_list[ii]->GetValue() != state )
229  rb_butt_list[ii]->SetValue( state );
230  }
231 }
232 
233 
235 {
237 
238  if( event.GetEventObject() == this )
240  else
241  m_matchAll->SetFocus();
242 }
243 
244 
246 {
248 
249  if( event.GetEventObject() == this )
251  else
252  m_matchSelected->SetFocus();
253 }
254 
255 
257 {
259 
260  if( event.GetEventObject() == this )
262  else if( event.GetEventObject() != m_specifiedRef )
263  m_specifiedRef->SetFocus();
264 }
265 
266 
268 {
270 
271  if( event.GetEventObject() == this )
273  else if( event.GetEventObject() != m_specifiedValue )
274  m_specifiedValue->SetFocus();
275 }
276 
277 
278 void DIALOG_EXCHANGE_FOOTPRINTS::OnMatchIDClicked( wxCommandEvent& event )
279 {
281 
282  if( event.GetEventObject() == this )
284  else if( event.GetEventObject() != m_specifiedID )
285  m_specifiedID->SetFocus();
286 }
287 
288 
289 void DIALOG_EXCHANGE_FOOTPRINTS::OnApplyClicked( wxCommandEvent& event )
290 {
291  wxBusyCursor dummy;
292 
294  m_MessageWindow->Flush( false );
295 
296  if( processMatchingModules() )
297  {
298  m_parent->Compile_Ratsnest( true );
299  m_parent->GetCanvas()->Refresh();
300  }
301 
302  m_MessageWindow->Flush( false );
303 
304  m_commit.Push( wxT( "Changed footprint" ) );
305 }
306 
307 
309 {
310  bool change = false;
311  LIB_ID newFPID;
312  wxString value;
313 
314  if( m_parent->GetBoard()->Modules().empty() )
315  return false;
316 
317  if( !m_updateMode )
318  {
319  newFPID.Parse( m_newID->GetValue(), LIB_ID::ID_PCB );
320 
321  if( !newFPID.IsValid() )
322  return false;
323  }
324 
325  /* The change is done from the last module because processModule() modifies the last item
326  * in the list.
327  */
328  for( auto it = m_parent->GetBoard()->Modules().rbegin();
329  it != m_parent->GetBoard()->Modules().rend(); it++ )
330  {
331  auto mod = *it;
332 
333  if( !isMatch( mod ) )
334  continue;
335 
336  if( m_updateMode )
337  {
338  if( processModule( mod, mod->GetFPID() ) )
339  change = true;
340  }
341  else
342  {
343  if( processModule( mod, newFPID ) )
344  change = true;
345  }
346  }
347 
348  return change;
349 }
350 
351 
352 bool DIALOG_EXCHANGE_FOOTPRINTS::processModule( MODULE* aModule, const LIB_ID& aNewFPID )
353 {
354  LIB_ID oldFPID = aModule->GetFPID();
355  wxString msg;
356 
357  // Load new module.
358  msg.Printf( _( "%s footprint \"%s\" (from \"%s\") to \"%s\"" ),
359  m_updateMode ? _( "Update" ) : _( "Change" ),
360  aModule->GetReference(),
361  oldFPID.Format().c_str(),
362  aNewFPID.Format().c_str() );
363 
364  MODULE* newModule = m_parent->LoadFootprint( aNewFPID );
365 
366  if( !newModule )
367  {
368  msg << ": " << _( "*** footprint not found ***" );
370  return false;
371  }
372 
373  m_parent->Exchange_Module( aModule, newModule, m_commit,
374  m_removeExtraBox->GetValue(),
375  m_resetTextItemLayers->GetValue(),
376  m_resetTextItemEffects->GetValue(),
377  m_reset3DModels->GetValue() );
378 
379  if( aModule == m_currentModule )
380  m_currentModule = newModule;
381 
382  msg += ": OK";
384 
385  return true;
386 }
387 
388 
389 void processTextItem( const TEXTE_MODULE& aSrc, TEXTE_MODULE& aDest,
390  bool resetText, bool resetTextLayers, bool resetTextEffects )
391 {
392  if( !resetText )
393  aDest.SetText( aSrc.GetText() );
394 
395  if( !resetTextLayers )
396  {
397  aDest.SetLayer( aSrc.GetLayer() );
398  aDest.SetVisible( aSrc.IsVisible() );
399  }
400 
401  if( !resetTextEffects )
402  {
403  // Careful: the visible bit is also in Effects
404  bool visible = aDest.IsVisible();
405  aDest.SetEffects( aSrc );
406  aDest.SetVisible( visible );
407  }
408 }
409 
410 
412 {
413  for( auto item : aModule->GraphicalItems() )
414  {
415  TEXTE_MODULE* candidate = dyn_cast<TEXTE_MODULE*>( item );
416 
417  if( candidate && candidate->GetText() == aRefItem->GetText() )
418  return candidate;
419  }
420 
421  return nullptr;
422 }
423 
424 
426  bool deleteExtraTexts, bool resetTextLayers,
427  bool resetTextEffects, bool reset3DModels )
428 {
429  aDest->SetParent( GetBoard() );
430 
431  PlaceModule( aDest, false );
432 
433  // PlaceModule will move the module to the cursor position, which we don't want. Copy
434  // the original position across.
435  aDest->SetPosition( aSrc->GetPosition() );
436 
437  if( aDest->GetLayer() != aSrc->GetLayer() )
438  aDest->Flip( aDest->GetPosition(), m_Settings->m_FlipLeftRight );
439 
440  if( aDest->GetOrientation() != aSrc->GetOrientation() )
441  aDest->Rotate( aDest->GetPosition(), aSrc->GetOrientation() );
442 
443  aDest->SetLocked( aSrc->IsLocked() );
444 
445  for( auto pad : aDest->Pads() )
446  {
447  D_PAD* oldPad = aSrc->FindPadByName( pad->GetName() );
448 
449  if( oldPad )
450  {
452  pad->SetNetCode( oldPad->GetNetCode() );
453  pad->SetPinFunction( oldPad->GetPinFunction() );
454  }
455  }
456 
457  // Copy reference
458  processTextItem( aSrc->Reference(), aDest->Reference(),
459  // never reset reference text
460  false,
461  resetTextLayers, resetTextEffects );
462 
463  // Copy value
464  processTextItem( aSrc->Value(), aDest->Value(),
465  // reset value text only when it is a proxy for the footprint ID
466  // (cf replacing value "MountingHole-2.5mm" with "MountingHole-4.0mm")
467  aSrc->GetValue() == aSrc->GetFPID().GetLibItemName(),
468  resetTextLayers, resetTextEffects );
469 
470  // Copy fields in accordance with the reset* flags
471  for( auto item : aSrc->GraphicalItems() )
472  {
473  TEXTE_MODULE* srcItem = dyn_cast<TEXTE_MODULE*>( item );
474 
475  if( srcItem )
476  {
477  TEXTE_MODULE* destItem = getMatchingTextItem( srcItem, aDest );
478 
479  if( destItem )
480  processTextItem( *srcItem, *destItem, false, resetTextLayers, resetTextEffects );
481  else if( !deleteExtraTexts )
482  aDest->Add( new TEXTE_MODULE( *srcItem ) );
483  }
484  }
485 
486  // Copy 3D model settings in accordance with the reset* flag
487  if( !reset3DModels )
488  aDest->Models() = aSrc->Models(); // Linked list of 3D models.
489 
490  // Updating other parameters
491  const_cast<KIID&>( aDest->m_Uuid ) = aSrc->m_Uuid;
492  aDest->SetPath( aSrc->GetPath() );
493  aDest->CalculateBoundingBox();
494 
495  aCommit.Remove( aSrc );
496  aCommit.Add( aDest );
497 
498  aDest->ClearFlags();
499 }
500 
501 
503 {
504  wxString newname = m_newID->GetValue();
505 
507 
508  if( frame->ShowModal( &newname, this ) )
509  {
510  if( event.GetEventObject() == m_newIDBrowseButton )
511  m_newID->SetValue( newname );
512  else
513  m_specifiedID->SetValue( newname );
514  }
515 
516  frame->Destroy();
517 }
518 
519 
bool g_resetTextItemLayers
void SetLazyUpdate(bool aLazyUpdate)
Sets the lasy update.
double GetOrientation() const
Definition: class_module.h:215
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:59
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
TEXTE_MODULE & Reference()
Definition: class_module.h:477
void OnMatchIDClicked(wxCommandEvent &event) override
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
int GetNetCode() const
Function GetNetCode.
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Function Rotate Rotate this object.
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:62
void Compile_Ratsnest(bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
std::string m_hash_key
Definition: dialog_shim.h:197
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
void CalculateBoundingBox()
Function CalculateBoundingBox calculates the bounding box in board coordinates.
bool IsVisible() const
Definition: eda_text.h:170
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void Flush(bool aSort=false)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true,...
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetVisible(bool aVisible)
Definition: eda_text.h:169
PADS & Pads()
Definition: class_module.h:173
const wxString GetValue() const
Function GetValue.
Definition: class_module.h:461
bool GetLocalRatsnestVisible() const
const LIB_ID & GetFPID() const
Definition: class_module.h:219
void SetLocalRatsnestVisible(bool aVisible)
const KIID_PATH & GetPath() const
Definition: class_module.h:228
bool g_reset3DModels
DRAWINGS & GraphicalItems()
Definition: class_module.h:183
void Exchange_Module(MODULE *aSrc, MODULE *aDest, BOARD_COMMIT &aCommit, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true, bool reset3DModels=true)
Function Exchange_Module Replaces OldModule by NewModule, using OldModule settings: position,...
const wxString & GetPinFunction() const
Definition: class_pad.h:211
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
bool IsValid() const
Definition: lib_id.h:171
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:115
This file contains miscellaneous commonly used macros and functions.
const wxString GetReference() const
Function GetReference.
Definition: class_module.h:436
const char * c_str() const
Definition: utf8.h:107
int g_matchModeForUpdateSelected
void OnMatchAllClicked(wxCommandEvent &event) override
bool processModule(MODULE *aModule, const LIB_ID &aNewFPID)
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
D_PAD * FindPadByName(const wxString &aPadName) const
Function FindPadByName returns a D_PAD* with a matching name.
#define ID_MATCH_FP_ID
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:111
Class DIALOG_EXCHANGE_FOOTPRINTS_BASE.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:341
#define ID_MATCH_FP_ALL
MODULES & Modules()
Definition: class_board.h:229
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:218
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:476
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.
Definition: string.cpp:433
DIALOG_EXCHANGE_FOOTPRINTS(PCB_EDIT_FRAME *aParent, MODULE *aModule, bool updateMode, bool selectedMode)
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
void OnMatchSelectedClicked(wxCommandEvent &event) override
#define ID_MATCH_FP_SELECTED
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
void SetPosition(const wxPoint &aPos) override
const BITMAP_OPAQUE small_library_xpm[1]
#define ID_MATCH_FP_REF
int g_matchModeForExchangeSelected
bool IsLocked() const override
Function IsLocked.
Definition: class_module.h:301
UTF8 Format() const
Definition: lib_id.cpp:237
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
void Report(const wxString &aText, SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Reports the string.
const KIID m_Uuid
Definition: base_struct.h:169
TEXTE_MODULE * getMatchingTextItem(TEXTE_MODULE *aRefItem, MODULE *aModule)
void updateMatchModeRadioButtons(wxUpdateUIEvent &event) override
bool g_resetTextItemEffects
PCBNEW_SETTINGS * m_Settings
std::list< MODULE_3D_SETTINGS > & Models()
Definition: class_module.h:205
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
void SetLocked(bool isLocked) override
Function SetLocked sets the MODULE_is_LOCKED bit in the m_ModuleStatus.
Definition: class_module.h:311
void Clear()
clears the report panel
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
#define _(s)
Definition: 3d_actions.cpp:33
void OnApplyClicked(wxCommandEvent &event) override
void OnMatchRefClicked(wxCommandEvent &event) override
#define ID_MATCH_FP_VAL
PCB_EDIT_FRAME is the main frame for Pcbnew.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void ViewAndSelectFootprint(wxCommandEvent &event) override
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:258
void SetEffects(const TEXTE_MODULE &aSrc)
Function SetEffects sets the text effects from another instance.
void processTextItem(const TEXTE_MODULE &aSrc, TEXTE_MODULE &aDest, bool resetText, bool resetTextLayers, bool resetTextEffects)
void SetPath(const KIID_PATH &aPath)
Definition: class_module.h:229
Module description (excepted pads)
BOARD * GetBoard() const
void PlaceModule(MODULE *aModule, bool aRecreateRatsnest=true)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
bool g_removeExtraTextItems
int g_matchModeForExchange
void OnMatchValueClicked(wxCommandEvent &event) override
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
const wxPoint GetPosition() const override
Definition: class_module.h:210
virtual bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
int g_matchModeForUpdate