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 <class_drawpanel.h>
30 #include <pcb_edit_frame.h>
31 #include <macros.h>
32 #include <board_commit.h>
33 #include <bitmaps.h>
34 #include <class_board.h>
35 #include <class_module.h>
36 #include <project.h>
37 #include <wx_html_report_panel.h>
38 #include <kiway.h>
39 
41 
42 
43 #define ID_MATCH_FP_ALL 4200
44 #define ID_MATCH_FP_SELECTED 4201
45 #define ID_MATCH_FP_REF 4202
46 #define ID_MATCH_FP_VAL 4203
47 #define ID_MATCH_FP_ID 4204
48 
49 
54 
55 
57  bool updateMode, bool selectedMode ) :
59  m_commit( aParent ),
60  m_parent( aParent ),
61  m_currentModule( aModule ),
62  m_updateMode( updateMode )
63 {
64  wxString title = updateMode ? _( "Update Footprints from Library" ) : _( "Change Footprints" );
65  wxString verb = updateMode ? _( "Update" ) : _( "Change" );
66  wxString label;
67 
68  SetTitle( title );
69 
70  if( m_updateMode )
71  {
72  label.Printf( m_matchAll->GetLabel(), verb );
73  m_matchAll->SetLabel( label );
74  m_changeSizer->Show( false );
75  }
76  else
77  {
78  m_upperSizer->FindItem( m_matchAll )->Show( false );
79  m_newIDBrowseButton->SetBitmap( KiBitmap( small_library_xpm ) );
80  }
81 
82  if( m_currentModule )
83  {
84  label.Printf( m_matchSelected->GetLabel(), verb );
85  m_matchSelected->SetLabel( label );
86  m_newID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
87  }
88  else
89  m_upperSizer->FindItem( m_matchSelected )->Show( false );
90 
91  label.Printf( m_matchSpecifiedRef->GetLabel(), verb );
92  m_matchSpecifiedRef->SetLabel( label );
93 
94  // Use ChangeValue() instead of SetValue() so we don't generate events.
95  if( m_currentModule )
96  m_specifiedRef->ChangeValue( m_currentModule->GetReference() );
97 
98  label.Printf( m_matchSpecifiedValue->GetLabel(), verb );
99  m_matchSpecifiedValue->SetLabel( label );
100 
101  if( m_currentModule )
102  m_specifiedValue->ChangeValue( m_currentModule->GetValue() );
103 
104  label.Printf( m_matchSpecifiedID->GetLabel(), verb );
105  m_matchSpecifiedID->SetLabel( label );
106 
107  if( m_currentModule )
108  m_specifiedID->ChangeValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
109 
110  m_specifiedIDBrowseButton->SetBitmap( KiBitmap( small_library_xpm ) );
111 
112  m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
113  m_upperSizer->RecalcSizes();
114 
115  // initialize match-mode
116  if( m_updateMode )
118  else
120 
121  wxCommandEvent event;
122  event.SetEventObject( this );
123 
124  switch( *m_matchMode )
125  {
126  case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
127  case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
128  case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
129  case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
130  case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
131  default: break;
132  }
133 
134  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
135  // because the update and change versions of this dialog have different controls.
136  m_hash_key = TO_UTF8( GetTitle() );
137 
138  // Ensure m_closeButton (with id = wxID_CANCEL) has the right label
139  // (to fix automatic renaming of button label )
140  m_sdbSizerCancel->SetLabel( _( "Close" ) );
141 
142  m_sdbSizerApply->SetDefault();
143 
144  // Now all widgets have the size fixed, call FinishDialogSettings
146 }
147 
148 
150 {
151  LIB_ID specifiedID;
152 
153  switch( *m_matchMode )
154  {
155  case ID_MATCH_FP_ALL:
156  return true;
158  return aModule == m_currentModule;
159  case ID_MATCH_FP_REF:
160  return WildCompareString( m_specifiedRef->GetValue(), aModule->GetReference(), false );
161  case ID_MATCH_FP_VAL:
162  return WildCompareString( m_specifiedValue->GetValue(), aModule->GetValue(), false );
163  case ID_MATCH_FP_ID:
164  specifiedID.Parse( m_specifiedID->GetValue(), LIB_ID::ID_PCB );
165  return aModule->GetFPID() == specifiedID;
166  default:
167  return false; // just to quiet compiler warnings....
168  }
169 }
170 
171 
173 {
174  switch( *m_matchMode )
175  {
176  case ID_MATCH_FP_ALL: return m_matchAll;
180  case ID_MATCH_FP_ID: return m_matchSpecifiedID;
181  default: return nullptr;
182  }
183 }
184 
185 
187 {
188  wxRadioButton* rb_button = getRadioButtonForMode();
189 
190  wxRadioButton* rb_butt_list[] =
191  {
192  m_matchAll,
197  nullptr // end of list
198  };
199 
200  // Ensure the button state is ok. Only one button can be checked
201  // Change button state only if its state is incorrect, otherwise
202  // we have issues depending on the platform.
203  for( int ii = 0; rb_butt_list[ii]; ++ii )
204  {
205  bool state = rb_butt_list[ii] == rb_button;
206 
207  if( rb_butt_list[ii]->GetValue() != state )
208  rb_butt_list[ii]->SetValue( state );
209  }
210 }
211 
212 
214 {
216 
217  if( event.GetEventObject() == this )
219  else
220  m_matchAll->SetFocus();
221 }
222 
223 
225 {
227 
228  if( event.GetEventObject() == this )
230  else
231  m_matchSelected->SetFocus();
232 }
233 
234 
236 {
238 
239  if( event.GetEventObject() == this )
241  else if( event.GetEventObject() != m_specifiedRef )
242  m_specifiedRef->SetFocus();
243 }
244 
245 
247 {
249 
250  if( event.GetEventObject() == this )
252  else if( event.GetEventObject() != m_specifiedValue )
253  m_specifiedValue->SetFocus();
254 }
255 
256 
257 void DIALOG_EXCHANGE_FOOTPRINTS::OnMatchIDClicked( wxCommandEvent& event )
258 {
260 
261  if( event.GetEventObject() == this )
263  else if( event.GetEventObject() != m_specifiedID )
264  m_specifiedID->SetFocus();
265 }
266 
267 
268 void DIALOG_EXCHANGE_FOOTPRINTS::OnApplyClicked( wxCommandEvent& event )
269 {
270  wxBusyCursor dummy;
271 
273  m_MessageWindow->Flush( true );
274 
275  if( processMatchingModules() )
276  {
278  m_parent->Compile_Ratsnest( NULL, true );
279 
280  m_parent->GetCanvas()->Refresh();
281  }
282 
283  m_commit.Push( wxT( "Changed footprint" ) );
284 }
285 
286 
288 {
289  MODULE* Module;
290  MODULE* PtBack;
291  bool change = false;
292  LIB_ID newFPID;
293  wxString value;
294 
295  if( !m_parent->GetBoard()->m_Modules )
296  return false;
297 
298  if( !m_updateMode )
299  {
300  newFPID.Parse( m_newID->GetValue(), LIB_ID::ID_PCB );
301 
302  if( !newFPID.IsValid() )
303  return false;
304  }
305 
306  /* The change is done from the last module because processModule() modifies the last item
307  * in the list.
308  * Note: for the first module in chain (the last here), Module->Back() points to the board
309  * or is NULL.
310  */
311  Module = m_parent->GetBoard()->m_Modules.GetLast();
312 
313  for( ; Module && Module->Type() == PCB_MODULE_T; Module = PtBack )
314  {
315  PtBack = Module->Back();
316 
317  if( !isMatch( Module ) )
318  continue;
319 
320  if( m_updateMode )
321  {
322  if( processModule( Module, Module->GetFPID()) )
323  change = true;
324  }
325  else
326  {
327  if( processModule( Module, newFPID ) )
328  change = true;
329  }
330  }
331 
332  return change;
333 }
334 
335 
336 bool DIALOG_EXCHANGE_FOOTPRINTS::processModule( MODULE* aModule, const LIB_ID& aNewFPID )
337 {
338  LIB_ID oldFPID = aModule->GetFPID();
339  REPORTER& reporter = m_MessageWindow->Reporter();
340  wxString msg;
341 
342  // Load new module.
343  msg.Printf( _( "%s footprint \"%s\" (from \"%s\") to \"%s\"" ),
344  m_updateMode ? _( "Update" ) : _( "Change" ),
345  aModule->GetReference(),
346  oldFPID.Format().c_str(),
347  aNewFPID.Format().c_str() );
348 
349  MODULE* newModule = m_parent->LoadFootprint( aNewFPID );
350 
351  if( !newModule )
352  {
353  msg << ": " << _( "*** footprint not found ***" );
354  reporter.Report( msg, REPORTER::RPT_ERROR );
355  return false;
356  }
357 
358  m_parent->Exchange_Module( aModule, newModule, m_commit,
359  m_removeExtraBox->GetValue(),
360  m_resetTextItemLayers->GetValue(),
361  m_resetTextItemEffects->GetValue() );
362 
363  if( aModule == m_currentModule )
364  m_currentModule = newModule;
365 
366  if( aModule == m_parent->GetCurItem() )
367  m_parent->SetCurItem( newModule );
368 
369  msg += ": OK";
370  reporter.Report( msg, REPORTER::RPT_ACTION );
371 
372  return true;
373 }
374 
375 
376 void processTextItem( const TEXTE_MODULE& aSrc, TEXTE_MODULE& aDest,
377  bool resetText, bool resetTextLayers, bool resetTextEffects )
378 {
379  if( !resetText )
380  aDest.SetText( aSrc.GetText() );
381 
382  if( !resetTextLayers )
383  {
384  aDest.SetLayer( aSrc.GetLayer() );
385  aDest.SetVisible( aSrc.IsVisible() );
386  }
387 
388  if( !resetTextEffects )
389  aDest.SetEffects( aSrc );
390 }
391 
392 
394 {
395  for( auto iItem = aModule->GraphicalItemsList().GetFirst(); iItem; iItem = iItem->Next() )
396  {
397  TEXTE_MODULE* candidate = dyn_cast<TEXTE_MODULE*>( iItem );
398 
399  if( candidate && candidate->GetText() == aRefItem->GetText() )
400  return candidate;
401  }
402 
403  return nullptr;
404 }
405 
406 
408  bool deleteExtraTexts,
409  bool resetTextLayers, bool resetTextEffects )
410 {
411  aDest->SetParent( GetBoard() );
412 
413  /* place module without ratsnest refresh: this will be made later
414  * when all modules are on board */
415  PlaceModule( aDest, nullptr, false );
416 
417  // Copy full placement and pad net names (when possible)
418  // but not local settings like clearances (use library values)
419  aSrc->CopyNetlistSettings( aDest, false );
420 
421  // Copy reference
422  processTextItem( aSrc->Reference(), aDest->Reference(),
423  // never reset reference text
424  false,
425  resetTextLayers, resetTextEffects );
426 
427  // Copy value
428  processTextItem( aSrc->Value(), aDest->Value(),
429  // reset value text only when it is a proxy for the footprint ID
430  // (cf replacing value "MountingHole-2.5mm" with "MountingHole-4.0mm")
431  aSrc->GetValue() == aSrc->GetFPID().GetLibItemName(),
432  resetTextLayers, resetTextEffects );
433 
434  // Copy fields in accordance with the reset* flags
435  for( BOARD_ITEM* item = aSrc->GraphicalItemsList().GetFirst(); item; item = item->Next() )
436  {
437  TEXTE_MODULE* srcItem = dyn_cast<TEXTE_MODULE*>( item );
438 
439  if( srcItem )
440  {
441  TEXTE_MODULE* destItem = getMatchingTextItem( srcItem, aDest );
442 
443  if( destItem )
444  processTextItem( *srcItem, *destItem, false, resetTextLayers, resetTextEffects );
445  else if( !deleteExtraTexts )
446  aDest->GraphicalItemsList().Append( new TEXTE_MODULE( *srcItem ) );
447  }
448  }
449 
450  // Updating other parameters
451  aDest->SetTimeStamp( aSrc->GetTimeStamp() );
452  aDest->SetPath( aSrc->GetPath() );
453 
454  aCommit.Remove( aSrc );
455  aCommit.Add( aDest );
456 
457  // @todo LEGACY should be unnecessary
458  GetBoard()->m_Status_Pcb = 0;
459  aDest->ClearFlags();
460 }
461 
462 
464 {
465  wxString newname = m_newID->GetValue();
466 
468 
469  if( frame->ShowModal( &newname, this ) )
470  {
471  if( event.GetEventObject() == m_newIDBrowseButton )
472  m_newID->SetValue( newname );
473  else
474  m_specifiedID->SetValue( newname );
475  }
476 
477  frame->Destroy();
478 }
479 
480 
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:120
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
TEXTE_MODULE & Reference()
Definition: class_module.h:503
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_player.h:60
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:53
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty.
Definition: dlist.h:170
std::string m_hash_key
Definition: dialog_shim.h:174
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
bool IsVisible() const
Definition: eda_text.h:189
Class BOARD to handle a board.
void Append(T *aNewElement)
Function Append adds aNewElement to the end of the list.
Definition: dlist.h:177
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:201
void SetVisible(bool aVisible)
Definition: eda_text.h:188
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
const LIB_ID & GetFPID() const
Definition: class_module.h:192
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
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:116
This file contains miscellaneous commonly used macros and functions.
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:47
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
class MODULE, a footprint
Definition: typeinfo.h:89
#define ID_MATCH_FP_ID
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:300
#define ID_MATCH_FP_ALL
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:216
void PlaceModule(MODULE *aModule, wxDC *aDC, bool aRecreateRatsnest=true)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:143
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:502
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:392
REPORTER & Reporter()
returns the reporter object that reports to this panel
DIALOG_EXCHANGE_FOOTPRINTS(PCB_EDIT_FRAME *aParent, MODULE *aModule, bool updateMode, bool selectedMode)
void OnMatchSelectedClicked(wxCommandEvent &event) override
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:462
timestamp_t GetTimeStamp() const
Definition: base_struct.h:207
#define ID_MATCH_FP_SELECTED
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
virtual EDA_DRAW_PANEL * GetCanvas() const
Definition: draw_frame.h:395
T * GetFirst() const
Function GetFirst returns the first T* in the list without removing it, or NULL if the list is empty.
Definition: dlist.h:163
#define ID_MATCH_FP_REF
int g_matchModeForExchangeSelected
UTF8 Format() const
Definition: lib_id.cpp:237
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:53
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
TEXTE_MODULE * getMatchingTextItem(TEXTE_MODULE *aRefItem, MODULE *aModule)
void updateMatchModeRadioButtons(wxUpdateUIEvent &event) override
BOARD_ITEM * Next() const
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
void Clear()
clears the report panel
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
DLIST< MODULE > m_Modules
Definition: class_board.h:249
void OnApplyClicked(wxCommandEvent &event) override
void OnMatchRefClicked(wxCommandEvent &event) override
MODULE * Back() const
Definition: class_module.h:123
#define ID_MATCH_FP_VAL
Class 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.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:487
void ViewAndSelectFootprint(wxCommandEvent &event) override
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
void SetEffects(const TEXTE_MODULE &aSrc)
Function SetEffects sets the text effects from another instance.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:165
void processTextItem(const TEXTE_MODULE &aSrc, TEXTE_MODULE &aDest, bool resetText, bool resetTextLayers, bool resetTextEffects)
void CopyNetlistSettings(MODULE *aModule, bool aCopyLocalSettings)
Function CopyNetlistSettings copies the netlist settings to aModule.
Module description (excepted pads)
BOARD * GetBoard() const
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
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
int g_matchModeForExchange
BOARD_ITEM * GetCurItem()
void OnMatchValueClicked(wxCommandEvent &event) override
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
VTBL_ENTRY 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...
void SetPath(const wxString &aPath)
Definition: class_module.h:202
void Exchange_Module(MODULE *aSrc, MODULE *aDest, BOARD_COMMIT &aCommit, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true)
Function Exchange_Module Replaces OldModule by NewModule, using OldModule settings: position,...
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:206
int g_matchModeForUpdate
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:241