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 <fctsys.h>
28 #include <kicad_string.h>
29 #include <pcb_edit_frame.h>
30 #include <macros.h>
31 #include <board_commit.h>
32 #include <bitmaps.h>
33 #include <class_board.h>
34 #include <class_module.h>
35 #include <project.h>
36 #include <wx_html_report_panel.h>
37 #include <kiway.h>
39 
40 
41 #define ID_MATCH_FP_ALL 4200
42 #define ID_MATCH_FP_SELECTED 4201
43 #define ID_MATCH_FP_REF 4202
44 #define ID_MATCH_FP_VAL 4203
45 #define ID_MATCH_FP_ID 4204
46 
47 
52 
54 bool g_resetTextItemLayers = false;
56 bool g_reset3DModels = false;
57 
58 
60  bool updateMode, bool selectedMode ) :
62  m_commit( aParent ),
63  m_parent( aParent ),
64  m_currentModule( aModule ),
65  m_updateMode( updateMode )
66 {
67  wxString title = updateMode ? _( "Update Footprints from Library" ) : _( "Change Footprints" );
68  wxString verb = updateMode ? _( "Update" ) : _( "Change" );
69  wxString label;
70 
71  SetTitle( title );
72 
73  if( m_updateMode )
74  {
75  label.Printf( m_matchAll->GetLabel(), verb );
76  m_matchAll->SetLabel( label );
77  m_changeSizer->Show( false );
78  }
79  else
80  {
81  m_upperSizer->FindItem( m_matchAll )->Show( false );
83  }
84 
85  if( m_currentModule )
86  {
87  label.Printf( m_matchSelected->GetLabel(), verb );
88  m_matchSelected->SetLabel( label );
89  m_newID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
90  }
91  else
92  m_upperSizer->FindItem( m_matchSelected )->Show( false );
93 
94  label.Printf( m_matchSpecifiedRef->GetLabel(), verb );
95  m_matchSpecifiedRef->SetLabel( label );
96 
97  // Use ChangeValue() instead of SetValue() so we don't generate events.
98  if( m_currentModule )
99  m_specifiedRef->ChangeValue( m_currentModule->GetReference() );
100 
101  label.Printf( m_matchSpecifiedValue->GetLabel(), verb );
102  m_matchSpecifiedValue->SetLabel( label );
103 
104  if( m_currentModule )
105  m_specifiedValue->ChangeValue( m_currentModule->GetValue() );
106 
107  label.Printf( m_matchSpecifiedID->GetLabel(), verb );
108  m_matchSpecifiedID->SetLabel( label );
109 
110  if( m_currentModule )
111  m_specifiedID->ChangeValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
112 
114 
115  m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
116  // The upper sizer has its content modified: re-layout it:
117  m_upperSizer->Layout();
118 
119  // initialize match-mode
120  if( m_updateMode )
122  else
124 
125  wxCommandEvent event;
126  event.SetEventObject( this );
127 
128  switch( *m_matchMode )
129  {
130  case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
131  case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
132  case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
133  case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
134  case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
135  default: break;
136  }
137 
141  m_reset3DModels->SetValue( g_reset3DModels );
142 
144 
145  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
146  // because the update and change versions of this dialog have different controls.
147  m_hash_key = TO_UTF8( GetTitle() );
148 
149  // Ensure m_closeButton (with id = wxID_CANCEL) has the right label
150  // (to fix automatic renaming of button label )
151  m_sdbSizerCancel->SetLabel( _( "Close" ) );
152 
153  m_sdbSizerApply->SetDefault();
154 
155  // Now all widgets have the size fixed, call FinishDialogSettings
157 }
158 
159 
161 {
165  g_reset3DModels = m_reset3DModels->GetValue();
166 }
167 
168 
170 {
171  LIB_ID specifiedID;
172 
173  switch( *m_matchMode )
174  {
175  case ID_MATCH_FP_ALL:
176  return true;
178  return aModule == m_currentModule;
179  case ID_MATCH_FP_REF:
180  return WildCompareString( m_specifiedRef->GetValue(), aModule->GetReference(), false );
181  case ID_MATCH_FP_VAL:
182  return WildCompareString( m_specifiedValue->GetValue(), aModule->GetValue(), false );
183  case ID_MATCH_FP_ID:
184  specifiedID.Parse( m_specifiedID->GetValue(), LIB_ID::ID_PCB );
185  return aModule->GetFPID() == specifiedID;
186  default:
187  return false; // just to quiet compiler warnings....
188  }
189 }
190 
191 
193 {
194  switch( *m_matchMode )
195  {
196  case ID_MATCH_FP_ALL: return m_matchAll;
200  case ID_MATCH_FP_ID: return m_matchSpecifiedID;
201  default: return nullptr;
202  }
203 }
204 
205 
207 {
208  wxRadioButton* rb_button = getRadioButtonForMode();
209 
210  wxRadioButton* rb_butt_list[] =
211  {
212  m_matchAll,
217  nullptr // end of list
218  };
219 
220  // Ensure the button state is ok. Only one button can be checked
221  // Change button state only if its state is incorrect, otherwise
222  // we have issues depending on the platform.
223  for( int ii = 0; rb_butt_list[ii]; ++ii )
224  {
225  bool state = rb_butt_list[ii] == rb_button;
226 
227  if( rb_butt_list[ii]->GetValue() != state )
228  rb_butt_list[ii]->SetValue( state );
229  }
230 }
231 
232 
234 {
236 
237  if( event.GetEventObject() == this )
239  else
240  m_matchAll->SetFocus();
241 }
242 
243 
245 {
247 
248  if( event.GetEventObject() == this )
250  else
251  m_matchSelected->SetFocus();
252 }
253 
254 
256 {
258 
259  if( event.GetEventObject() == this )
261  else if( event.GetEventObject() != m_specifiedRef )
262  m_specifiedRef->SetFocus();
263 }
264 
265 
267 {
269 
270  if( event.GetEventObject() == this )
272  else if( event.GetEventObject() != m_specifiedValue )
273  m_specifiedValue->SetFocus();
274 }
275 
276 
277 void DIALOG_EXCHANGE_FOOTPRINTS::OnMatchIDClicked( wxCommandEvent& event )
278 {
280 
281  if( event.GetEventObject() == this )
283  else if( event.GetEventObject() != m_specifiedID )
284  m_specifiedID->SetFocus();
285 }
286 
287 
288 void DIALOG_EXCHANGE_FOOTPRINTS::OnApplyClicked( wxCommandEvent& event )
289 {
290  wxBusyCursor dummy;
291 
293  m_MessageWindow->Flush( false );
294 
295  if( processMatchingModules() )
296  {
297  m_parent->Compile_Ratsnest( true );
298  m_parent->GetCanvas()->Refresh();
299  }
300 
301  m_MessageWindow->Flush( false );
302 
303  m_commit.Push( wxT( "Changed footprint" ) );
304 }
305 
306 
308 {
309  bool change = false;
310  LIB_ID newFPID;
311  wxString value;
312 
313  if( m_parent->GetBoard()->Modules().empty() )
314  return false;
315 
316  if( !m_updateMode )
317  {
318  newFPID.Parse( m_newID->GetValue(), LIB_ID::ID_PCB );
319 
320  if( !newFPID.IsValid() )
321  return false;
322  }
323 
324  /* The change is done from the last module because processModule() modifies the last item
325  * in the list.
326  */
327  for( auto it = m_parent->GetBoard()->Modules().rbegin();
328  it != m_parent->GetBoard()->Modules().rend(); it++ )
329  {
330  auto mod = *it;
331 
332  if( !isMatch( mod ) )
333  continue;
334 
335  if( m_updateMode )
336  {
337  if( processModule( mod, mod->GetFPID() ) )
338  change = true;
339  }
340  else
341  {
342  if( processModule( mod, newFPID ) )
343  change = true;
344  }
345  }
346 
347  return change;
348 }
349 
350 
351 bool DIALOG_EXCHANGE_FOOTPRINTS::processModule( MODULE* aModule, const LIB_ID& aNewFPID )
352 {
353  LIB_ID oldFPID = aModule->GetFPID();
354  wxString msg;
355 
356  // Load new module.
357  msg.Printf( _( "%s footprint \"%s\" (from \"%s\") to \"%s\"" ),
358  m_updateMode ? _( "Update" ) : _( "Change" ),
359  aModule->GetReference(),
360  oldFPID.Format().c_str(),
361  aNewFPID.Format().c_str() );
362 
363  MODULE* newModule = m_parent->LoadFootprint( aNewFPID );
364 
365  if( !newModule )
366  {
367  msg << ": " << _( "*** footprint not found ***" );
369  return false;
370  }
371 
372  m_parent->Exchange_Module( aModule, newModule, m_commit,
373  m_removeExtraBox->GetValue(),
374  m_resetTextItemLayers->GetValue(),
375  m_resetTextItemEffects->GetValue(),
376  m_reset3DModels->GetValue() );
377 
378  if( aModule == m_currentModule )
379  m_currentModule = newModule;
380 
381  msg += ": OK";
383 
384  return true;
385 }
386 
387 
388 void processTextItem( const TEXTE_MODULE& aSrc, TEXTE_MODULE& aDest,
389  bool resetText, bool resetTextLayers, bool resetTextEffects )
390 {
391  if( !resetText )
392  aDest.SetText( aSrc.GetText() );
393 
394  if( !resetTextLayers )
395  {
396  aDest.SetLayer( aSrc.GetLayer() );
397  aDest.SetVisible( aSrc.IsVisible() );
398  }
399 
400  if( !resetTextEffects )
401  {
402  // Careful: the visible bit is also in Effects
403  bool visible = aDest.IsVisible();
404  aDest.SetEffects( aSrc );
405  aDest.SetVisible( visible );
406  }
407 }
408 
409 
411 {
412  for( auto item : aModule->GraphicalItems() )
413  {
414  TEXTE_MODULE* candidate = dyn_cast<TEXTE_MODULE*>( item );
415 
416  if( candidate && candidate->GetText() == aRefItem->GetText() )
417  return candidate;
418  }
419 
420  return nullptr;
421 }
422 
423 
425  bool deleteExtraTexts, bool resetTextLayers,
426  bool resetTextEffects, bool reset3DModels )
427 {
428  aDest->SetParent( GetBoard() );
429 
430  PlaceModule( aDest, false );
431 
432  // PlaceModule will move the module to the cursor position, which we don't want. Copy
433  // the original position across.
434  aDest->SetPosition( aSrc->GetPosition() );
435 
436  if( aDest->GetLayer() != aSrc->GetLayer() )
437  aDest->Flip( aDest->GetPosition(), m_configSettings.m_FlipLeftRight );
438 
439  if( aDest->GetOrientation() != aSrc->GetOrientation() )
440  aDest->Rotate( aDest->GetPosition(), aSrc->GetOrientation() );
441 
442  aDest->SetLocked( aSrc->IsLocked() );
443 
444  for( auto pad : aDest->Pads() )
445  {
446  D_PAD* oldPad = aSrc->FindPadByName( pad->GetName() );
447 
448  if( oldPad )
449  {
451  pad->SetNetCode( oldPad->GetNetCode() );
452  pad->SetPinFunction( oldPad->GetPinFunction() );
453  }
454  }
455 
456  // Copy reference
457  processTextItem( aSrc->Reference(), aDest->Reference(),
458  // never reset reference text
459  false,
460  resetTextLayers, resetTextEffects );
461 
462  // Copy value
463  processTextItem( aSrc->Value(), aDest->Value(),
464  // reset value text only when it is a proxy for the footprint ID
465  // (cf replacing value "MountingHole-2.5mm" with "MountingHole-4.0mm")
466  aSrc->GetValue() == aSrc->GetFPID().GetLibItemName(),
467  resetTextLayers, resetTextEffects );
468 
469  // Copy fields in accordance with the reset* flags
470  for( auto item : aSrc->GraphicalItems() )
471  {
472  TEXTE_MODULE* srcItem = dyn_cast<TEXTE_MODULE*>( item );
473 
474  if( srcItem )
475  {
476  TEXTE_MODULE* destItem = getMatchingTextItem( srcItem, aDest );
477 
478  if( destItem )
479  processTextItem( *srcItem, *destItem, false, resetTextLayers, resetTextEffects );
480  else if( !deleteExtraTexts )
481  aDest->Add( new TEXTE_MODULE( *srcItem ) );
482  }
483  }
484 
485  // Copy 3D model settings in accordance with the reset* flag
486  if( !reset3DModels )
487  aDest->Models() = aSrc->Models(); // Linked list of 3D models.
488 
489  // Updating other parameters
490  aDest->SetTimeStamp( aSrc->GetTimeStamp() );
491  aDest->SetPath( aSrc->GetPath() );
492  aDest->CalculateBoundingBox();
493 
494  aCommit.Remove( aSrc );
495  aCommit.Add( aDest );
496 
497  aDest->ClearFlags();
498 }
499 
500 
502 {
503  wxString newname = m_newID->GetValue();
504 
506 
507  if( frame->ShowModal( &newname, this ) )
508  {
509  if( event.GetEventObject() == m_newIDBrowseButton )
510  m_newID->SetValue( newname );
511  else
512  m_specifiedID->SetValue( newname );
513  }
514 
515  frame->Destroy();
516 }
517 
518 
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...
const wxString & GetPath() const
Definition: class_module.h:228
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)
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:79
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:226
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:216
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
void Report(const wxString &aText, REPORTER::SEVERITY aSeverity, REPORTER::LOCATION aLocation=REPORTER::LOC_BODY)
Reports the string.
timestamp_t GetTimeStamp() const
Definition: base_struct.h:213
#define ID_MATCH_FP_SELECTED
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
PCB_GENERAL_SETTINGS m_configSettings
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
TEXTE_MODULE * getMatchingTextItem(TEXTE_MODULE *aRefItem, MODULE *aModule)
void updateMatchModeRadioButtons(wxUpdateUIEvent &event) override
bool g_resetTextItemEffects
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:31
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:256
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)
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
void SetPath(const wxString &aPath)
Definition: class_module.h:229
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:212
int g_matchModeForUpdate